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

发布于 2025-01-17 23:53:04 字数 691 浏览 3 评论 0原文

我知道我需要定义一个虚拟析构函数(即使我的类是final也是最好的选择)。 就我而言,我使用类似 C 的结构(没有函数,没有默认值,只有普通成员)并使用继承来组成新结构。然后,我将指向基类的指针存储在 std::unique_ptr 中,并让 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;
}

I know that I need to define a virtual destructor (best option even if my class is final).
In my case, I am using C-like structures (no functions, no defaults, just plain members) and use inheritance to compose a new structure. I then store a pointer to the base class in std::unique_ptr and let RAII do the rest.

I am now curious if there is a need to also explicitely add a virtual destructor to avoid memory problems.

An example might be:

#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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一指流沙 2025-01-24 23:53:04

班级是多态还是微不足道都没关系。

如果delete在不同类型的指针上调用(直至CV合并),而不是它指向的对象的最衍生的类型,而指向型的对象则没有虚拟destructor ,那么行为是不确定的。

此规则的一个明显原因是,基类子对象可能不在与最衍生的对象的地址相同的地址。因此,编译器将无法知道要传递给DealLocation函数的偏移是什么。

也许有人可能会争辩说,如果使用指向第一基类子对象的指针,则具有微不足道驱动器的标准类别不需要遵循此规则,但是该标准并未使其异常,并且您的类c c 无论如何都不是标准的。

参见

It doesn't matter whether the class is polymorphic or whether it is trivial.

If delete is called on a pointer of different type (up to cv-qualification) than the most-derived type of the object it points to and the pointed-to-type doesn't have a virtual destructor, then the behavior is undefined.

One obvious reason for this rule is that the base class subobject might not be located at the same address as the most-derived object. So the compiler would have no way of knowing what the offset to pass to the deallocation function needs to be.

One could maybe argue that a standard-layout class with trivial destructor would not need to follow this rule if a pointer to the first base class subobject is used, but the standard doesn't make that exception and your class C isn't standard-layout anyway.

See CWG issue 1259 closed as not-a-defect. The size-aware global deallocation functions mentioned in the issue were also introduced with C++14, which is another reason that using a base class pointer may cause you problems in practice, even if the destructor is trivial and the address without offset.

酒中人 2025-01-24 23:53:04

如果您使用sharon_ptr而不是unique_ptr,那么当创建第一个指针而不创建sharone_ptr的eleter时,这将起作用当指针在shared_ptr实例之间复制时更改。这不适用于unique_ptr,它将使用std :: Default_delete&lt; t&gt;其中tsimory_ptr t /代码>实例不是最初构建的类型。

参见 https://godbolt.org/z/tjp6dbo9g 代码>失败和shared_ptr工作。

If you use shared_ptr rather than unique_ptr then this will work as the deleter of the shared_ptr is created when the first pointer is created and doesn't change when the pointer is copied between shared_ptr instances. This doesn't apply in unique_ptr which will use std::default_delete<T> where T is the type of the unique_ptr instance not the type originally constructed.

See https://godbolt.org/z/TjP6dbo9G for some examples of unique_ptr failing and shared_ptr working.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文