#include <iostream>
struct ABC{
int A;
ABC(int i = 1) : A(i) {}
~ABC() {
std::cout << A << std::endl;
}
void destruct() {
delete this;
}
};
int main() {
ABC A1(2);
A1.destruct();
return 0;
}
Output:
2
2
我有这个代码,我试图手动删除结构变量。这样做,我意识到析构函数在这里被调用了两次。为什么会这样?为什么在调用destruct()
时不会删除它?
答案 0 :(得分:6)
delete this
来电导致undefined behaviour,这意味着任何事情都可能发生。
delete
只能用于由new
创建的对象。
对于具有非平凡析构函数的自动对象(例如,您的A1
),不可能及早销毁它们&#34;除非您在范围结束之前在同一位置创建另一个ABC
。换句话说,你不能关闭&#34;范围结束时发生的销毁过程。
答案 1 :(得分:2)
这是RAII工作加上你对一个物体自杀。在对象上调用析构函数几乎总是错误的!并且两次调用析构函数总是错误的,因为它调用了未定义的行为。
你必须明白C ++正在为你处理内存,如果你只是让它:
struct Foo{};
int main() {
Foo f; // automatic storage, gets destroyed
// when object gets out of scope
Foo* g = new Foo(); // heap allocated
delete g; // only here you have to delete
}
请记住:不要delete
通过new
创建的任何内容(感谢Mike Vine的评论)。除非你需要,否则不要使用(裸)堆分配。
答案 2 :(得分:2)
为什么在调用
destruct()
时不会删除[我的对象]?
当一个对象在C ++中被破坏时,并不意味着该对象消失。这意味着析构函数中的清理代码会被执行,并且从该点开始对对象成员的任何访问都是无效的。
当您致电destruct()
时,您会尝试通过拨打delete
来释放对象的内存。这本身就是未定义的行为,因为您尚未使用new
分配对象。此调用会导致第一次打印输出。
但是,由于您的对象位于自动内存中,因此当对象超出范围时,需要C ++调用其析构函数。这是导致第二次打印输出的调用。
注意:您可以通过在动态内存中分配A1
来修复代码:
int main() {
ABC *A1 = new ABC(2);
A1->destruct();
return 0;
}
现在你得到一个打印输出(demo)。但是,将delete
隐藏在成员函数中的做法是值得怀疑的。
答案 3 :(得分:1)
这里要考虑两点: -
1)堆栈对象的析构函数在超出范围时将始终被调用。所以不必担心他们的解除分配。
2)你不能&amp;不应该在堆栈上分配的对象上使用delete。一般情况下,只要您不确定仅在删除堆对象的情况下执行此操作,并且之后您没有引用该对象,就不应该使用delete this
。