当前位置: 首页 > 知识库问答 >
问题:

c++ - C++中未初始化指针调用成员函数为何未报错反而执行了?

罗安和
2024-08-21

#include <iostream>
using namespace std;
class BBB {
public:
    void print() {
        cout << "1234" << endl;
    }
};


class InitPtrClass {
public:
    void init_ptr() {};
    void use_ptr() {
        if (bbb == nullptr) {
            cout << "s" << endl;
        }
        bbb->print();
    };
private:
    BBB *bbb = nullptr;
};

int main()
{
    InitPtrClass ipc;
    ipc.use_ptr();
    return 0;
}

为什么这段代码会打印出1234,编译运行,不应该报错么?

如题

共有2个答案

钮誉
2024-08-21

这是 未定义行为 。

未定义行为并不是一定会崩溃,而是什么都可能发生。具体会发生啥跟编译器/编译选项/体系结构...都有关系。

温智明
2024-08-21

在你的代码中,实际上存在一个明显的逻辑错误,该错误导致未初始化的指针 bbb 被错误地解引用并调用了其成员函数 print(),但你的代码实际上包含了一个检查 bbb 是否为 nullptr 的条件语句,这个条件语句应该阻止未初始化指针的解引用。然而,由于条件语句的位置和代码逻辑,这个检查实际上并没有阻止 print() 函数的调用。

这里是问题所在:

void use_ptr() {
    if (bbb == nullptr) {
        cout << "s" << endl;
    }
    bbb->print(); // 这行代码无条件执行,不依赖于前面的if语句
};

use_ptr() 函数中,你首先检查 bbb 是否为 nullptr,并在是的情况下打印 "s"。然而,无论 bbb 是否为 nullptr,接下来的 bbb->print(); 都会执行。这意味着如果 bbbnullptrbbb->print(); 仍然会尝试解引用一个空指针,这通常会导致运行时错误(如段错误或访问违规)。

然而,在你的代码中,由于 bbb 已经在类中初始化为 nullptr,并且没有其他代码在 use_ptr() 调用之前修改 bbb 的值,理论上它应该打印 "s" 并随后崩溃(或者在某些编译器/运行环境下表现为未定义行为,可能包括不崩溃并错误地执行了 print(),但这实际上是一个错误或异常行为)。

为什么你看到了 "1234" 而不是崩溃?

有几种可能的原因,但最常见的是你的代码在运行时环境或编译器中有某种异常或未定义行为的表现。例如,内存可能已经被分配并初始化为某种状态,使得 bbb->print(); 实际上调用了一个有效的 print() 方法(尽管这是一个非常罕见和危险的情况)。然而,更可能的是,你的代码或测试环境中有一些未显示的部分(如其他函数或全局变量)影响了 bbb 的值,或者你的测试环境以某种方式掩盖了崩溃。

如何修复?

你应该将 bbb->print(); 放在 if 语句的 else 部分,以确保在 bbb 不是 nullptr 时才调用它:

void use_ptr() {
    if (bbb == nullptr) {
        cout << "s" << endl;
    } else {
        bbb->print();
    }
};

这样,如果 bbbnullptr,则不会尝试解引用它,从而避免运行时错误。

 类似资料:
  • 为什么定义num时初始化或者用初始化函数Stu_t都会导致报错? 是不是意味着 union 内所有的成员以及嵌套的所有成员都不能在定义时初始化和使用构造函数呢? 如果不让初始化则会不会导致内存里是随机数据呢? 对 union 内成员逐层嵌套的成员进行定义时初始化和使用构造函数验证,发现都会报错。

  • 我已经检查过自己,我写了一个这样的程序 我运行了几次程序,结果始终是一样的,零。我在C中尝试过,结果是一样的。 但我的教科书说 如果未初始化函数内定义的变量,则该变量值将保持未定义状态。这意味着该元素具有以前驻留在内存中该位置的任何值。 当程序始终将可用内存位置分配给变量时,这怎么可能?它怎么可能是零以外的东西(我假设默认的可用内存值为零)?

  • thread_test.cpp:32:22:注意:候选项为: /usr/include/c++/4.6/thread:133:7:注意:std::thread::thread(_callable&&,_args&&...)[with_callable=void(a::*)(),_args={}] /usr/include/c++/4.6/线程:133:7:注意:参数1从''到'void(A::*&

  • 我在中用C创建了一个包含10个元素的数组,并仅为其中一些元素声明了值。当打印出数组时,我注意到其中一个元素(保持不变)没有初始化为零。相反,每次都将其初始化为不同的大值(即)。然后,我注释掉了所有代码,只保留了最初声明的数组。 运行代码时,数组的前8个元素被初始化为零,数组中的第9个元素被初始化为一个大值(如),该值每次都会更改,最后一个元素被一致地初始化为相同的非零数字。 有人知道为什么会这样吗

  • 现在,我知道没有内联的保证,但是。。。 给定以下内容: 我们有: 编译成: 然而... 编译成: 这真的很让人难过。 为什么打给PMF的电话没有被内联?PMF是一个不变的表情!

  • 这个问题的后续问题 我们有以下代码: 这种访问是一种未定义的行为吗?一方面,不需要对象来访问静态类成员,另一方面,

  • 根据此堆栈溢出问题的公认(且唯一)答案, 使用 将改为零初始化对象。 那么,为什么呢?, 生成此输出: 定义的两个构造函数都是默认的?正当对于POD类型,默认初始化为零初始化。 根据这个问题的公认答案, 如果POD成员未在构造函数中初始化,也未在类初始化中通过C11初始化,则默认为已初始化。 不管是堆栈还是堆,答案都是一样的。 在C 98中(而不是之后),new int()被指定为执行零初始化。

  • 如果我有一个struct Foo和一个struct Bar: 如果我初始化一个条并打印正确得到的值: 但是现在如果我声明这样的构造函数: 我失去了Bar::foo的默认构造,程序输出了32764 0 5! 为什么我不得不像这样无声地初始化每个成员变量: 只要我声明一个构造函数?在这种情况下,为什么默认构造不起作用?