可能重复:
Why the below piece of code is not crashing , though i have deleted the object?
今天我发现我对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?
答案 0 :(得分:10)
有两种方法可以回答您的问题:
您的代码有未定义的行为
它取消引用NULL
或delete
ed指针。根据C ++标准,它们都调用Undefined Behavior。它的工作与否是毫无意义的
未定义的行为意味着任何行为都是可能的,它可能会或可能不会崩溃,但这意味着您的程序无法提供任何明确定义的输出。它只是意味着任何行为都是可能的,并且可能不一致或定义得很好。
它不会崩溃,因为编译器在调用成员函数时实际上不会解除this
。除非函数是virtual
函数,否则编译器会将this
作为第一个参数传递给函数,从而将成员函数调用转换为通常的函数调用。它可以这样做,因为编译器可以准确地确定在编译时自己调用哪个函数。所以实际上,通过已删除或NULL
指针调用成员函数不会取消引用this
(如果NULL
或delete
编辑,则无效)。此外,只有在函数体内访问任何成员时才会取消引用this
在您的情况下,您永远不会访问函数体内的任何成员,因此它不会崩溃
添加一个成员并在你的函数中取消引用它,它肯定会崩溃。
无论如何,在实际答案中所说的技术答案已经超越了一切,因为标准说明了这一点。
答案 1 :(得分:3)
为什么不崩溃?
您通过取消引用已删除的指针来调用未定义的行为。未定义的行为意味着您的程序可以执行任何。任何事情都不包括崩溃。
如果未定义的行为总是意味着您的程序立即崩溃,那么它将很容易调试和修复。未定义行为的最严重问题之一是程序在测试时看起来可以正常工作,然后当您将它发送给客户时,它们会得到您无法重现的异常行为。即使事情似乎在你的机器上运行,你也应该总是避免调用未定义的行为。
答案 2 :(得分:2)
这只是未定义的行为,其中包括发生重大崩溃的可能性!
不多说,但标准中的引用可能有助于未定义行为的含义:
本国际标准没有要求的行为[注:未定义 当本国际标准遗漏任何行为时,可能会出现这种行为 行为的明确定义或程序使用错误的时间 构造或错误的数据。允许的未定义行为范围 从无法预测的结果完全忽略这种情况到 在记录中的翻译或程序执行期间表现 环境的方式特征(有或没有发行 (诊断消息),终止翻译或执行 (发布诊断信息)。许多错误的计划 构造不会产生未定义的行为;他们必须是 诊断。 - 结束说明]