我有一段代码,我可以多次调用析构函数并访问成员函数,甚至在保留成员变量值的情况下调用析构函数。在调用delete
之后,我仍然能够访问成员函数,但成员变量无效(全部为0)。我不能加倍delete
。请解释一下。
#include <iostream>
using namespace std;
template <typename T>
void destroy(T* ptr)
{
ptr->~T();
}
class Testing
{
public:
Testing() : test(20)
{
}
~Testing()
{
printf("Testing is being killed!\n");
}
int getTest() const
{
return test;
}
private:
int test;
};
int main()
{
Testing *t = new Testing();
cout << "t->getTest() = " << t->getTest() << endl;
destroy(t);
cout << "t->getTest() = " << t->getTest() << endl;
t->~Testing();
cout << "t->getTest() = " << t->getTest() << endl;
delete t;
cout << "t->getTest() = " << t->getTest() << endl;
destroy(t);
cout << "t->getTest() = " << t->getTest() << endl;
t->~Testing();
cout << "t->getTest() = " << t->getTest() << endl;
//delete t; // <======== Don't do it! Double free/delete!
cout << "t->getTest() = " << t->getTest() << endl;
return 0;
}
答案 0 :(得分:16)
这是未定义行为的展示。通过一个已删除的指针调用成员函数,任何事情都会发生 - 编译器和运行时不需要检查这个错误,但你当然不能指望这个工作。
这与使用已释放的内存属于类似类别 - 您可能会在那里找到旧数据(或者您可能不会)。您可能会导致程序崩溃(或不崩溃)。您甚至可以在没有任何抱怨的情况下更改数据。
但无论如何,这是一个编程错误。
答案 1 :(得分:6)
仅仅因为您访问不再有效的对象并不意味着您的程序已爆炸,这只意味着您的程序可以爆炸。
这是未定义的行为,这意味着任何事情都可能发生,甚至可能看起来做正确的事情。
答案 2 :(得分:5)
“一次调用析构函数 对象,对象不再存在; 如果是,行为是不确定的 为对象调用析构函数 其寿命已经结束“
C++ draft standard§12.4.12
正如其他人所指出的,这并不意味着实现总是会做一些明显不需要的事情(比如分段错误)。这意味着它可以做任何最方便的事情。
答案 3 :(得分:2)
您调用了未定义的行为,所有投注都已关闭。
答案 4 :(得分:2)
你真的不应该调用类的析构函数(除非你使用了placement new)然而回答你的问题,一旦删除了内存,访问指向该内存的指针会导致未定义的行为。在您的情况下,似乎您正在使用的内存已被释放以供将来使用,但它尚未被覆盖。所以你仍然能够访问它,但是不能保证何时该内存将被其他东西使用。
答案 5 :(得分:1)
正如在destroy()
中那样,直接在main()
中调用析构函数实际上并不会导致在C ++中销毁对象。只有此代码中的delete
语句才能执行此操作。由于T的析构函数是良性的(它只是打印),这几乎没有效果。
由于没有成员函数是虚拟的,因此在销毁之后调用它们仍然会找到正确的代码来执行。在那里,this
指针可能无效(在您调用delete
之后),但这并不会阻止代码取消引用指针并返回int
成员值的值