C++:使用仅具有属性的继承结构时是否需要实现虚拟析构函数?

C++: Implementation of virtual destructor necessary when using inherited structs with only properties?

我知道我需要定义一个虚拟析构函数(最好的选择,即使我的 class 是 final)。 就我而言,我正在使用类似 C 的结构(没有函数,没有默认值,只有普通成员)并使用继承来组成一个新结构。然后我在 std::unique_ptr 中存储一个指向基 class 的指针,让 RAII 完成剩下的工作。

我现在很好奇是否还需要显式添加虚拟析构函数以避免内存问题。

例如:

#include <chrono>
#include <memory>

struct A {
    std::chrono::milliseconds duration = std::chrono::milliseconds{-1};
    int count = 0;
};

struct B {
    int mode = 0;
};

struct C : public A, public B {
    int foo = 1;
};

int main()
{
   std::unique_ptr<A> base = std::make_unique<C>();
   base.reset(); // I expect here that A,B and C are destructed properly

   return 0;
}

class 是多态的还是平凡的都没有关系。

如果 delete 是在与它指向的对象的 most-derived 类型不同类型(最多 cv-qualification)的指针上调用的,而 pointed-to-type 则不没有虚拟析构函数,则行为未定义。

此规则的一个明显原因是基础 class 子对象可能与 most-derived 对象不在同一地址。因此编译器无法知道传递给释放函数的偏移量需要是多少。

有人可能会争辩说,如果使用指向第一个基 class 子对象的指针,具有普通析构函数的 standard-layout class 不需要遵循此规则,但是标准没有例外,你的 class C 也不是 standard-layout。

参见 CWG issue 1259 关闭为 not-a-defect。问题中提到的 size-aware 全局释放函数也在 C++14 中引入,这是使用基 class 指针可能会给您带来实际问题的另一个原因,即使析构函数是微不足道的并且没有偏移量的地址。

如果您使用 shared_ptr 而不是 unique_ptr 那么这将起作用,因为 shared_ptr 的删除器是在创建第一个指针时创建的,并且在创建指针时不会更改在 shared_ptr 个实例之间复制。这不适用于将使用 std::default_delete<T>unique_ptr,其中 Tunique_ptr 实例的类型,而不是最初构造的类型。

有关 unique_ptr 失败和 shared_ptr 工作的一些示例,请参阅 https://godbolt.org/z/TjP6dbo9G