【问题标题】:Does Explicitly Calling Child Destructors also call Parent Destructors显式调用子析构函数是否也调用父析构函数
【发布时间】:2014-10-25 18:59:42
【问题描述】:

对于我用 C++ 编写的内存管理器作为概念证明,为了跟踪分配的对象,我在函数中使用 malloc() 分配内存,然后返回指向该内存的指针并使用放置新运营商。然后,为了跟踪对象何时被删除,我将指针传递给另一个函数以在指针上调用free()

但是,由于我使用free() 而不是delete,对象的构造函数不会像通常那样自动调用,所以我必须自己调用它。此外,由于内存管理器设计用于处理任何对象,因此可以想象(甚至可能)在其生命周期的某个时刻,它必须释放一个可能具有多个父类或位于继承树深处的对象。

我最初的解决方案是调用基础对象析构函数,这将调用所有子析构函数(如果相信this question),但因为对象实际上可以是任何东西并且具有任何继承集,没有办法知道它的真正基类是什么。

所以我的问题是:显式调用子类析构函数是否也会自动调用所有基本析构函数,例如删除,还是没有办法轻松做到这一点?

【问题讨论】:

  • 与手动调用构造函数相比,自动调用析构函数的行为没有区别(至少,我不知道)。不过,证明(使用标准语言)可能会很棘手。
  • 你可以很容易地写一些代码来找出答案。
  • @PaulRooney 那不给你任何保证。

标签: c++ memory memory-management


【解决方案1】:

是的,这是有保证的。 C++14 [class.dtor]/8:

在执行析构函数的主体并销毁主体内分配的任何自动对象后,X 类的析构函数调用X 的直接非变量非静态数据成员的析构函数,@ 的析构函数987654323@ 的直接基类,如果 X 是最派生类 (12.6.2) 的类型,则其析构函数调用 X 的虚拟基类的析构函数。

具体来说,对于任何类型 T,您始终可以这样做:

void * addr = ::operator new(sizeof T);
T * p = ::new (addr) T(/* ctor args */);
p->~T();                                    // !
::operator delete(addr);

或者,如果您不想调用分配器:

{
    std::aligned_storage_t<sizeof(T), alignof(T)> storage;
    T * p = ::new (static_cast<void *>(std::addressof(storage))) T(/* args */);
    p->~T();
}

【讨论】:

  • 我实际上有两个简单的问题。 1. 这适用于 C++14,但它是否也适用于我正在使用的 C++11? 2. 这说它会这样做,但它没有明确说这将发生在显式调用中,所以这是有保证的还是只是在谈论delete
  • @sm81095: 1) 是的,2) 这不是在谈论delete;它在谈论析构函数。
  • 好的,太棒了!感谢您快速而直接的回答。我将对此进行大量测试,但由于它是标准的一部分,我希望一切都能正常工作。
  • @sm81095:就算了吧。这是该语言整个对象模型的一个如此深刻的核心部分,以至于编译器完全无法想象其中的任何部分都会出错。
猜你喜欢
  • 2021-01-28
  • 2011-04-28
  • 2014-10-23
  • 2012-09-02
  • 2013-06-25
  • 1970-01-01
  • 2017-02-08
相关资源
最近更新 更多