如何可能(如果可以的话)实现shared_ptr而不需要多态类具有虚拟析构函数?
Lidström 先生的主张是构造 shared_ptr
不需要 Base 有虚拟析构函数:
Armen Tsirunyan:“真的吗?shared_ptr会正确清理吗?在这种情况下,您能否演示一下如何实现该效果?”
Daniel Lidström:“shared_ptr 使用自己的析构函数来删除 Concrete 实例。这在 C++ 社区中称为 RAII。我的建议是您学习所有内容当您在所有情况下使用 RAII 时,您可以了解 RAII。”
Armen Tsirunyan:“我了解 RAII,而且我也知道最终 shared_ptr 析构函数可能会在 pn 达到 0 时删除存储的 px。但是如果 px 具有静态指向
Base
的类型指针和指向Derived
的动态类型指针,那么除非Base
有虚拟析构函数,否则这将导致未定义的行为。我错了。”Daniel Lidström:“shared_ptr 知道静态类型是 Concrete。自从我在其构造函数中传递它以来,它就知道这一点!看起来有点像魔术,但我可以向您保证,这是经过设计的,而且非常漂亮。”
所以,评判我们吧。在不要求多态类具有虚拟析构函数的情况下,如何可能(如果可以的话)实现shared_ptr?
Mr. Lidström and I had an argument :)
Mr. Lidström's claim is that a construct shared_ptr<Base> p(new Derived);
doesn't require Base to have a virtual destructor:
Armen Tsirunyan: "Really? Will the shared_ptr clean up correctly? Could you please in this case demonstrate how that effect could be implemented?"
Daniel Lidström: "The shared_ptr uses its own destructor to delete the Concrete instance. This is known as RAII within the C++ community. My advice is that you learn all you can about RAII. It will make your C++ coding so much easier when you use RAII in all situations."
Armen Tsirunyan: "I know about RAII, and I also know that eventually the shared_ptr destructor may delete the stored px when pn reaches 0. But if px had static type pointer to
Base
and dynamic type pointer toDerived
, then unlessBase
has a virtual destructor, this will result in undefined behavior. Correct me if I am wrong."Daniel Lidström: "The shared_ptr knows the static type is Concrete. It knows this since I passed it in its constructor! Seems a bit like magic, but I can assure you it is by design and extremely nice."
So, judge us. How is it possible (if it is) to implement shared_ptr without requiring polymorphic classes to have virtual destructor?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,可以通过这种方式实现shared_ptr。 Boost 确实如此,C++11 标准也要求这种行为。作为增加的灵活性,shared_ptr 不仅仅管理引用计数器。所谓的删除器通常被放入也包含引用计数器的同一内存块中。但有趣的是,这个删除器的类型不是shared_ptr类型的一部分。这称为“类型擦除”,基本上与用于实现“多态函数”
boost::function
或std::function
用于隐藏实际函子类型的技术相同。为了使您的示例正常工作,我们需要一个模板化构造函数:因此,如果您将其与您的类
Base
和Derived
一起使用......模板化构造函数与
Y=Derived
用于构造shared_ptr
对象。因此,构造函数有机会创建适当的删除器对象和引用计数器,并将指向该控制块的指针存储为数据成员。如果引用计数器达到零,则先前创建的且派生
感知的删除器将用于处置该对象。C++11 标准对此构造函数有以下规定 (20.7.2.2.1):
对于析构函数(20.7.2.2.2):
(使用粗体字体强调的是矿)。
Yes, it is possible to implement shared_ptr that way. Boost does and the C++11 standard also requires this behaviour. As an added flexibility shared_ptr manages more than just a reference counter. A so-called deleter is usually put into the same memory block that also contains the reference counters. But the fun part is that the type of this deleter is not part of the shared_ptr type. This is called "type erasure" and is basically the same technique used for implementing the "polymorphic functions"
boost::function
orstd::function
for hiding the actual functor's type. To make your example work, we need a templated constructor:So, if you use this with your classes
Base
andDerived
...... the templated constructor with
Y=Derived
is used to construct theshared_ptr
object. The constructor has thus the chance to create the appropriate deleter object and reference counters and stores a pointer to this control block as a data member. If the reference counter reaches zero, the previously created andDerived
-aware deleter will be used to dispose of the object.The C++11 standard has the following to say about this constructor (20.7.2.2.1):
And for the destructor (20.7.2.2.2):
(emphasis using bold font is mine).
当创建
shared_ptr
时,它会在其内部存储一个deleter对象。当shared_ptr
即将释放指向的资源时调用此对象。由于您知道如何在构造时销毁资源,因此即使对于不完整的类型,您也可以使用shared_ptr
。创建shared_ptr
的人已经在那里存储了正确的删除器。例如,您可以创建一个自定义删除器:
p
将调用DeleteDerived
来销毁指向的对象。这是
shared_ptr
构造函数自动执行的操作,因此在实践中,您不需要实现此类删除器,除非您通过调用delete
以外的方式进行释放。When
shared_ptr
is created it stores a deleter object inside itself. This object is called when theshared_ptr
is about to free the pointed resource. Since you know how to destroy the resource at the point of construction you can useshared_ptr
even with incomplete types. Whoever created theshared_ptr
has already stored a correct deleter there.For example, you can create a custom deleter:
p
will callDeleteDerived
to destroy the pointed object.This is what the
shared_ptr
constructor does automatically, so in practice you don't need to implement that sort of a deleter unless you free by means other than a call todelete
.简单地说,
shared_ptr
使用特殊的删除器函数,该函数由始终使用的构造函数创建给定对象的析构函数而不是 Base 的析构函数,这是模板元编程的一些工作,但它有效。
类似的东西
Simply,
shared_ptr
uses special deleter function that is created by constructor that always usesthe destructor of the given object and not the destructor of Base, this is a bit of work with template meta programming, but it works.
Something like that