`delete this;`语句中发生了什么?

时间:2012-01-11 13:44:03

标签: c++ memory

请考虑以下代码:

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会导致异常或堆损坏吗?

7 个答案:

答案 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)

我对你释放记忆的背景非常谨慎。虽然叫“删除这个;”将尝试释放与类结构相关联的内存,该操作无法推断原始内存分配的上下文,即,是否从堆或堆栈分配。我的建议是重做代码,以便从外部上下文调用释放操作。请注意,这与释放类内部结构不同,在这种情况下,请使用析构函数。