请考虑以下代码:
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();
}
选项1中的第二个delete a;
语句是否会导致异常或堆损坏?
option2会导致异常或堆损坏吗?
答案 0 :(得分:20)
delete this;
,删除对象。
您的代码片段都有未定义的行为 - 在第一种情况下删除已删除的对象,在第二种情况下删除具有自动存储持续时间的对象。
由于行为未定义,标准没有说明它们是否会导致异常或堆损坏。对于不同的实现,它可以是,也可以是两者,或者两者都没有,并且每次运行代码时它可能相同或不同。
答案 1 :(得分:4)
两者都会导致错误。
第一个指针被删除两次,第二个delete
导致错误,而第二个在堆栈上分配,无法隐式删除(由于首次调用析构函数导致错误)。
答案 2 :(得分:3)
这个问题已经得到解答但是我会添加一个新的观点,如果你的类确实调用了delete this,那么你也应该将析构函数设为私有。
这确保只有类可以自行删除。
如果您将析构函数设置为私有,则两个代码示例都将无法编译。
答案 3 :(得分:1)
两者都会导致错误,你想要的是:
void main()
{
foo* a = new foo();
a->done();
}
编译器将扩展到类似下面的内容,我希望删除“this”有点不那么混乱。
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?
答案 4 :(得分:1)
调用delete this
是一个坏主意。致电new
的人应致电delete
。因此,其他答复中强调了这些问题。
在构造对象数组时,也可能出现内存泄漏/未定义的行为。
答案 5 :(得分:0)
在这两种情况下,您的堆都会被破坏。当然,你不能在选项2“ - >”中使用如果左值(在这种情况下,“a”)不是指针,则选项2中的正确形式将是a.done(); 但是,如果你试图删除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
。
答案 6 :(得分:0)
我对你释放记忆的背景非常谨慎。虽然叫“删除这个;”将尝试释放与类结构相关联的内存,该操作无法推断原始内存分配的上下文,即,是否从堆或堆栈分配。我的建议是重做代码,以便从外部上下文调用释放操作。请注意,这与释放类内部结构不同,在这种情况下,请使用析构函数。