虚拟析构函数与虚拟成员在C ++ 11 [英] Virtual destructor with virtual members in C++11

查看:161
本文介绍了虚拟析构函数与虚拟成员在C ++ 11的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这些幻灯片中关于C ++ 11/14标准,幻灯片15,作者写道许多经典的编码规则在C ++ 11中不再适用。他提出了三个例子的列表,我同意三原则和内存管理。

In these slides about C++11/14 standard, on slide 15, the author writes that "many classic coding rules [are] no longer applicable" in C++11. He proposes a list of three examples, and I agree with the Rule of Three and the memory management.

但是他的第二个例子是虚拟成员的虚拟析构函数那)。 这是什么意思?我知道必须声明为虚拟的基类析构函数,以便调用正确的析构函数,如果我们有像

However his second example is "Virtual destructor with virtual members" (just that). What does it mean? I know one must declare as virtual the base class destructor in order to call the right destructor if we have something like

Base *b = new Derived;
...
delete b;

这里有很好的解释:何时使用虚拟析构器?

但是现在在C ++ 11中声明

But is it useless now in C++11 to declare virtual your destructor if you have virtual members?

推荐答案

作为幻灯片的作者,我将尝试澄清。

As the author of the slides I'll try to clarify.

如果您编写代码明确地分配 Derived 实例与 new 并使用基类指针使用 delete 删除它,那么您需要定义一个 virtual 析构函数,否则结束不完全破坏 Derived 实例。但是,我建议完全弃用 new delete ,并使用 shared_ptr 用于引用堆分配的多态对象,例如

If you write code explicitly allocating a Derived instance with new and destroying it with delete using a base class pointer then you need to define a virtual destructor, otherwise you end up with incompletely destroying the Derived instance. However, I recommend to abstain from new and delete completely and use exclusively shared_ptr for referring to heap-allocated polymorphic objects, like

shared_ptr<Base> pb=make_shared<Derived>();

这样,共享指针会跟踪要使用的原始析构函数,即使 shared_ptr< Base> 用于表示它。一旦,最后一个引用 shared_ptr 超出范围或被重置,〜Derived()将被调用,释放。因此,您不需要使〜Base() virtual。

This way, the shared pointer keeps track of the original destructor to be used, even if shared_ptr<Base> is used to represent it. Once, the last referring shared_ptr goes out of scope or is reset, ~Derived() will be called and the memory released. Therefore, you don't need to make ~Base() virtual.

unique_ptr< ; Base> make_unique< Derived> 不提供此功能,因为它们不提供 shared_ptr 相对于删除器,因为唯一指针更简单,并且目标是最低的开销,因此不存储删除器所需的额外的函数指针。使用 unique_ptr ,deleter函数是类型的一部分,因此具有指向〜Derived 的删除程序的uniqe_ptr不会与 unique_ptr< Base> 兼容使用默认的deleter,如果〜Base 不是虚拟的。

unique_ptr<Base> and make_unique<Derived> do not provide this feature, because they don't provide the mechanics of shared_ptr with respect to the deleter, because unique pointer is much simpler and aims for the lowest overhead and thus is not storing the extra function pointer needed for the deleter. With unique_ptr the deleter function is part of the type and thus a uniqe_ptr with a deleter referring to ~Derived would not be compatible with a unique_ptr<Base> using the default deleter, which would be wrong for a derived instance anyway, if ~Base wasn't virtual.

我所提出的个人建议是很容易遵循和遵循的。

The individual suggestions I make, are meant to be easy to follow and followed all together. They try to produce simpler code, by letting all resource management be done by library components and the compiler generated code.

在类中定义一个(虚拟)析构函数会禁止一个类中的(虚拟)析构函数,编译器提供的移动构造函数/赋值运算符,并且可能禁止编译器在C ++的未来版本中提供复制构造函数/赋值运算符。使用 = default 很容易恢复它们,但仍然看起来像很多样板代码。最好的代码是你不必写的代码,因为它不会错误(我知道这个规则还有例外)。

Defining a (virtual) destructor in a class, will prohibit a compiler-provided move constructor/assignment operator and might prohibit also a compiler provided copy constructor/assignment operator in future versions of C++. Resurrecting them has become easy with =default, but still looks like a lot of boilerplate code. And the best code is the code you don't have to write, because it can not be wrong (I know there are still exceptions to that rule).

总结不要定义一个(虚拟)析构函数作为我的零规则的推论:

To summarize "Don't define a (virtual) destructor" as a corollary to my "Rule of Zero":

无论何时你在现代C ++中设计一个多态并希望/需要在堆上分配它的实例,并通过基类类指针使用 make_shared< Derived>()来实例化它们和 shared_ptr< ; Base> 来保存它们。这允许你保持零规则。

Whenever you design a polymorphic (OO) class hierarchy in modern C++ and want/need to allocate its instances on the heap and access them through a base class pointer use make_shared<Derived>() to instantiate them and shared_ptr<Base> to keep them around. This allows you to keep the "Rule of Zero".

这并不意味着你必须在堆上分配所有的多态对象。例如,定义一个以(Base&)为参数的函数,可以使用局部 Derived Base

This doesn't mean you must allocate all polymorphic objects on the heap. For example, defining a function taking a (Base&) as parameter, can be called with a local Derived variable without problems and will behave polymorphic, with respect to virtual member functions of Base.

在我看来,动态OO多态是在许多系统中严重过度使用。我们不应该像Java一样编程,当我们使用C ++,除非我们有一个问题,其中动态多态与堆分配的对象是正确的解决方案。

In my opinion dynamic OO polymorphism is heavily overused in many systems. We shouldn't program like Java, when we use C++, unless we have a problem, where dynamic polymorphism with heap allocated objects is the right solution.

这篇关于虚拟析构函数与虚拟成员在C ++ 11的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆