【问题标题】:C++ destructor: when the memory gets freed?C++ 析构函数:何时释放内存?
【发布时间】:2011-01-26 00:34:54
【问题描述】:

如果我删除一个导致其析构函数被调用的对象,内存是在析构函数完成函数中的任何操作之前还是之后释放?

【问题讨论】:

    标签: c++ destructor


    【解决方案1】:

    只有在最小派生类子对象被销毁后才会释放内存。所以如果你有:

    class Base {
    };
    
    class Derived : public Base {
    public:
        ~Derived();
    };
    

    然后首先 Derived 被销毁,然后 Base 被销毁,然后才释放内存。

    【讨论】:

    • 真的有这种事吗?调用一个特定的析构函数,如果类声明它是虚拟的,它可能是虚拟的。该析构函数负责销毁所有子对象,然后释放内存。所有没有基类的子对象都是派生最少的,没有一个具有特定的责任或意义。
    • @Potatoswatter:请注意,我没有具体说明谁负责调用解除分配函数 - 正是因为这样做在所有细节上都需要两页的答案。
    • @Potatoswatter:我不确定我是否遵循。没有析构函数负责销毁子对象。析构函数负责释放该对象中持有的资源,但不必(也不应该)调用其他对象的析构函数:class test { string a; ~test() {} }; ~test 析构函数在此示例中完美定义,没有资源直接由班级管理,什么也不做。在~test 完成执行后,系统将在a 子对象上调用~string,而不是~test。继承也是一样,会自动调用base的析构函数。
    • ... 请注意,必须处理的是让 most derived class 的析构函数被调用。完成之后,系统将确保所有base 的析构函数都以相反的构造顺序被调用。回到责任上,如果一个成员拥有一个需要特定管理的资源,并且该资源不被该类型的析构函数持有——想想一个需要 delete 的指针,并且作为一个指针没有析构函数—— - 然后该资源必须在包含类中进行管理。
    • @David:“没有析构函数负责销毁子对象。”好吧,不是明确的,不:您不必在~Derived() 内明确调用this->~Base()。但是,至少按照正式定义的方式,~Derived() 负责调用this->~Base()(以及您的评论示例中的a.~string())。当您使用delete 时,会调用一个析构函数,该析构函数负责调用所有清理,包括在需要时调用任何基类或成员析构函数。
    【解决方案2】:

    delete分解成它实际在做的事情,看看什么时候删除内存就比较清楚了。所以这样的声明:

    delete some_ptr;
    

    大致相当于这个伪代码:

    some_ptr->~some_ptr();
    free( some_ptr );
    

    所以内存在调用析构函数后被释放。析构函数的确切作用不是由delete 运算符决定,而是由类的定义决定。通常它会进行本地清理并确保其基类析构函数也被调用。

    重要的是要意识到释放内存实际上并不是析构函数的一部分。释放内存的是delete 运算符。


    请注意,伪代码中的free 函数实际上是operator delete() 函数之一,用于已删除的类或全局。这实际上释放了内存。

    【讨论】:

    • 那不是free(),那是operator delete()
    • @sharptooth,你能澄清一下吗?我确实提到那是“伪代码”。
    • 即使是伪代码 C++ 也使用 operator delete() - 全局或特定于类 - 在 delete 语句上释放内存。
    • 是的,这是正确的,虽然对于伪代码我认为“免费”更容易理解(那里没有递归删除)
    • @sharptooth:很难用自身来描述一个运算符。只要您提到它是伪代码,使用 free() 作为示例是可以接受的。虽然我会使用 release() 来防止与任何特定 API 混淆。
    【解决方案3】:

    在析构函数完成后,内存被释放。否则,在析构函数中访问成员变量会导致段错误。

    【讨论】:

      【解决方案4】:

      在析构函数之后调用操作符delete,但释放内存时取决于使用的分配器

      【讨论】:

        【解决方案5】:

        我认为在析构函数本身完成执行后释放内存。我知道当捕获到异常时,直到对象本身超出范围时才会调用对象的析构函数。

        【讨论】:

          【解决方案6】:

          在 C++ 中,销毁是关于使用对象中可用的数据执行一些代码。这段代码是任意的。

          释放内存是一种低级处理,通常被 delete 运算符隐藏,绝不应在调用析构函数之前调用它。

          Allocator 接口最好总结了这一点:

          • allocatedeallocate 用于操作原始内存
          • constructdestroy用于调用对象的构造函数和析构函数

          确切地说,constructdestroydeallocate 只能在该分配器先前分配的内存上执行。它还明确指出destroy 不会释放内存,并且随后需要调用deallocate

          请注意,这是一个低级接口,它允许销毁一个对象并重用释放的空间来构建另一个对象。

          【讨论】:

            猜你喜欢
            • 2016-10-25
            • 2017-08-19
            • 1970-01-01
            • 1970-01-01
            • 2014-11-12
            • 1970-01-01
            • 2017-05-25
            • 2013-01-04
            • 1970-01-01
            相关资源
            最近更新 更多