C++:使用仅具有属性的继承结构时是否需要实现虚拟析构函数?
我知道我需要定义一个虚拟析构函数(即使我的类是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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
班级是多态还是微不足道都没关系。
如果
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.
如果您使用
sharon_ptr
而不是unique_ptr
,那么当创建第一个指针而不创建sharone_ptr
的eleter时,这将起作用当指针在shared_ptr
实例之间复制时更改。这不适用于unique_ptr
,它将使用std :: Default_delete&lt; t&gt;
其中t
是simory_ptr
t
/代码>实例不是最初构建的类型。参见 https://godbolt.org/z/tjp6dbo9g 代码>失败和
shared_ptr
工作。If you use
shared_ptr
rather thanunique_ptr
then this will work as the deleter of theshared_ptr
is created when the first pointer is created and doesn't change when the pointer is copied betweenshared_ptr
instances. This doesn't apply inunique_ptr
which will usestd::default_delete<T>
whereT
is the type of theunique_ptr
instance not the type originally constructed.See https://godbolt.org/z/TjP6dbo9G for some examples of
unique_ptr
failing andshared_ptr
working.