虚拟析构函数与虚拟成员在C ++ 11 [英] Virtual destructor with virtual members in 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屋!