【问题标题】:Does calling delete from inside a destructor cause stack overflow?从析构函数内部调用 delete 会导致堆栈溢出吗?
【发布时间】:2012-06-14 06:37:16
【问题描述】:

以下代码创建一个指向B* 的双指针B**。它将使用该指针为另一个指针分配内存,该指针将指向在调用start() 时创建的B 实例:

class A:

class A
{
public:
    A()
    {
        fb = new B*;
        *fb = NULL;
    }

    ~A()
    {
        if(*fb)
            delete *fb;

        delete fb;
    }

    B** getfb()
    {
        return fb;
    }

private:
    B** fb;
};

class B:

class B
{
public:
    B()
    {
        B** fb = a->getfb();

        *fb = this;
    }

    ~B()
    {
        B** fb = a->getfb();

        delete *fb;            // <--- stack overflow

        *fb = NULL;
    }

private:
    A* a;
};

start()class C的成员函数):

void C::start()
{
    B** fb = a->getfb();        // 'a' is a pointer to an 'A' instance

    if(*fb == NULL)
        B* f = new B;
}

所以,每当我调用start() 然后再调用~B() 时,都会出现堆栈溢出!

【问题讨论】:

  • 第一个问题:你知道delete是做什么的吗?
  • 我认为只有在析构函数中调用 exit() 时才会发生递归
  • exit 游戏结束。基本上,在它之后没有调用任何东西(嗯,……)。
  • 没有。相信我——或者更好试试看。如果您依赖exit 调用您的析构函数,请为内存泄漏做好准备。

标签: c++ memory-management stack-overflow destructor


【解决方案1】:

听起来不错。

fb 的类型是B**,所以*fb 的类型是B*

因此,当您说 delete *fb 时,您正在调用 class B 的析构函数,这是一个递归调用,不会对基本情况取得进展,因此堆栈溢出。

【讨论】:

    【解决方案2】:

    B() 中分配*fb = this; 然后:

    ~B()
    {
      ...
      delete *fb; // delete this;
      ...
    }
    

    .. 相当于在析构函数~B() 中一次又一次地调用delete this;,因此由于递归函数太多而导致stackoveflow。

    这是Is it safe to delete this 的一个不错的帖子。

    【讨论】:

    • 嗯,那里排名最高的回复中的结论(delete this 通常被认为是糟糕的形式,并且有难闻的气味)显然是错误的。根据事务的管理方式,delete this 可能是大多数删除的最干净和最好的方式。 (当然是最OO的——对象自己负责。)
    【解决方案3】:

    这并不奇怪。您在 B 类的析构函数中,访问当前正在调用其析构函数的 B 的相同实例,然后再次将其删除。这将导致析构函数调用中的递归,从而导致堆栈溢出。您在 A 类删除 fb 足以清理您的记忆,您不希望 B 类自行删除。

    您也不需要在 B 类构造函数中执行您正在执行的操作。你在 A 类中的代码是有道理的,你在 B 类中的代码是危险的和不必要的。在 B 类中,您没有设置其成员 a 的功能。这意味着指针未初始化,然后您尝试将此 B 类实例分配给 A 的此 未初始化 实例的 B 类成员指针。

        B()
        {
            B** fb = a->getfb(); // a never gets set to a meaningful value!!!!!
    
            *fb = this;
        }
    

    【讨论】:

    • 因为没有初始化a,我已经注意到我只是希望代码尽可能清晰。我想你是对的,我应该把所有的东西都写对了。谢谢你的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-15
    • 2011-02-08
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-06
    相关资源
    最近更新 更多