`delete this;`语句期间发生了什么?在以下两个选项 class foo { public: foo(){} ~foo(){} void done() { delete this;} private: int x; };
class foo { public: foo(){} ~foo(){} void done() { delete this;} private: int x; };
正在发生的事情(而且是有效的吗?):
选项1:
void main()
{
foo* a = new foo();
a->done();
delete a;
}
选项2:
void main()
{
foo a;
a.done();
}
请问第二个delete a;
声明在opt离子1会导致异常或堆腐败?
option2是否会导致异常或堆损坏?
delete this;
是允许的,它删除对象。
这两个代码片段都具有未定义的行为 - 第一种情况是删除已删除的对象,第二种情况是删除具有自动存储持续时间的对象。
由于行为未定义,因此标准并未说明它们是否会导致异常或堆损坏。对于不同的实现,它可能既不是,也不是两者都有,并且每次运行代码时可能也可能不一样。
希望它会是前者。 – Xeo 2012-01-11 13:55:12
未定义的行为,最好的和正确的答案。 +1 – 2012-01-11 13:57:20
双方将导致一个错误,你想要的是:
void main()
{
foo* a = new foo();
a->done();
}
,编译器将扩展到类似下面,我希望品牌删去“本”少了几分扑朔迷离。
void __foo_done(foo* this)
{
delete this;
}
void main()
{
foo* a = new foo();
__foo_done(a);
}
参见,Is it legal (and moral) for a member function to say delete this?
调用delete this
是一个坏主意。无论谁打电话new
应拨打delete
。因此,其他答复中突出强调的问题。
也可以在构造对象数组时使用内存泄漏/未定义的行为。
为什么要调用'delete this'是一个坏主意?我会说在很多(大多数?)应用程序中,它将是最常见的'delete'形式。 – 2012-01-11 14:19:57
@JamesKanze为什么? '删除这个'不是正常的释放对象的方法。 – 2012-01-11 14:34:19
@VJovic这取决于应用程序。在很多应用程序中,最常见的(甚至是唯一的)'delete's将会是'delete this'。在其他情况下,'delete'将系统地位于交易管理器中,或类似的东西。而在其他...这取决于你为什么使用动态内存。如果是模型对象,那么'删除这个'或一个事务管理器是最常见的。如果是复杂的数据结构,那么结构的所有者将执行'delete',并且'delete this'几乎不会发生。 – 2012-01-11 15:43:11
在这两种情况下,你的堆将被损坏。当然,如果左值(在本例中为“a”)不是指针,选项2中的正确形式为a.done(),那么不能在选项2“ - >”中使用。 但是,是的,如果您尝试删除1)已被删除的内容或2)本地变量,您应该得到一个堆损坏。
调用“删除这个”在技术上是有效的,并释放内存。
编辑我很好奇,实际上尝试这样:
class foo
{
public:
foo(){}
~foo(){}
void done() { delete this; }
void test() { x = 2; }
int getx() { return x; }
private:
int x;
} ;
int main(int argc, char* argv[])
{
foo *a = new foo();
a->done();
a->test();
int x = a->getx();
printf("%i\n", x);
return x;
}
到printf
的调用会成功,x
将持有的价值2
。
我会非常谨慎的关于你释放内存的上下文。虽然称“删除此;”将尝试释放与类结构关联的内存,该操作无法推断原始内存分配的上下文,即,是否从堆或堆栈中分配。我的建议是重写你的代码,以便从外部上下文中调用解除分配操作。请注意,这与释放类内部的结构不同,在这种情况下,请使用析构函数。
这个问题已经回答了,但我会添加一个新点,如果你的类确实调用delete this,那么你也应该使析构函数保密。
这确保只有类可以删除自己。
如果您在上面隐藏析构函数,那么您的两个代码示例都将无法编译。
当然它并不能防止所有的错误,例如在调用done()之后使用该对象(即使再次调用done()也会调用双重删除)。 – CashCow 2012-01-11 15:11:45
您是否错误地忘记了该类的开头括号,还是完全是复制粘贴代码? – Neophile 2012-01-11 13:46:06
@Nerds:错字 - 修正... – NirMH 2012-01-11 13:46:50
有趣。我猜第一个会导致segfault或堆corrupetion,第二个会做任何删除指向堆栈的指针。 – cha0site 2012-01-11 13:50:17