5

可能重复:
为什么下面的代码没有崩溃,虽然我已经删除了对象?

今天我发现我对 C++ 内存管理一无所知。请看一下这段代码:

class A
{
 public:
     A(){std::cout << "constructor called" << this << std::endl;}
    ~A(){std::cout << "destructor called" << this << std::endl;}
      void test (){std::cout << "test" << this << std::endl;}
 };

 int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

A *aa = new A();

delete aa;
aa->test();
aa->test();
aa->test();
std::cout << "still works\n";
return a.exec();
}

为什么不崩溃?为什么尽管调用了析构函数,它仍然继续执行?当我调用test方法时,我会处理不再属于应用程序的内存。

更令人惊讶的是,即使我在aa = NULL;之后插入它仍然有效delete aa;test方法被调用好了。我必须承认我完全糊涂了。如果没有效果,析构函数和分配 NULL 的目的是什么?

4

3 回答 3

10

为什么这行得通?

有两种方法可以回答您的问题:

技术答案:

您的代码具有未定义的行为
它取消引用 aNULLdeleteed 指针。根据 C++ 标准,两者都调用未定义的行为。它是否有效是没有意义的。
未定义的行为意味着任何行为都是可能的,它可能会或可能不会崩溃,但这意味着您的程序不能期望给出任何明确定义的输出。它只是意味着任何行为都是可能的,并且可能不一致或定义不明确。

实用答案:

它不会崩溃,因为编译器this在调用成员函数时实际上并没有取消引用。除非函数是virtual函数,否则编译器会将成员函数调用转换为通常的函数调用,方法是将this其作为第一个参数传递给函数。它可以这样做是因为编译器可以准确地确定在编译时调用哪个函数。所以实际上,通过 delete 或NULL指针调用成员函数不会取消引用this如果它NULLdeleteed则无效)。此外,this只有在函数体内访问任何成员时才会取消引用。
在您的情况下,您永远不会访问函数体内的任何成员,因此它不会崩溃。
在你的函数中添加一个成员并取消引用它,它肯定会崩溃。

无论如何,在实际答案中所说的技术答案是高于一切的,因为标准是这样说的。

于 2012-12-23T14:24:13.773 回答
3

为什么不崩溃?

您通过取消引用已删除的指针来调用未定义的行为。未定义的行为意味着您的程序可以做任何事情。任何事情都包括不崩溃。

如果未定义的行为总是意味着您的程序立即崩溃,那么调试和修复将很容易。未定义行为最令人讨厌的问题之一是,当您测试程序时,程序看起来可以正常工作,然后当您将其发送给客户时,他们会出现您无法重现的异常行为。即使事情似乎在您的机器上运行,您也应该始终避免调用未定义的行为。

于 2012-12-23T14:23:50.567 回答
2

那只是未定义的行为,其中包括发生大崩溃的可能性!

无需多说,但标准中的引用可能有助于未定义行为的含义:

1.3.24 未定义的行为

behavior for which this International Standard imposes no requirements [ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. — end note ]

于 2012-12-23T14:24:23.057 回答