shared_ptr魔法:) [英] shared_ptr magic :)

查看:208
本文介绍了shared_ptr魔法:)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

先生Lidström和我有一个参数:)



Lidström的声明是一个构造 shared_ptr< Base> p(new Derived); 不需要Base有一个虚拟析构函数:


Tsirunyan :真的吗? shared_ptr 是否正确清理?在这种情况下,你能否证明如何实现这种效果?



DanielLidström shared_ptr 使用自己的析构函数来删除Concrete实例,这在C ++社区中被称为RAII我的建议是,



Armen Tsirunyan :我可以使用RAII,知道RAII,并且我也知道当pn达到0时, shared_ptr 析构函数可能会删除存储的px。但是如果px有静态类型指针 Base 和动态类型指针 Derived ,那么除非 Base 有一个虚拟析构函数,否则会导致未定义的行为。



DanielLidström shared_ptr 知道静态类型是Concrete。它知道这,因为我通过它的构造函数!看起来有点像魔术,但我可以向你保证它是由设计和非常好的。


可以(如果是)实现 shared_ptr 而不需要多态类具有虚拟析构函数?
提前感谢

解决方案

是的,可以实现shared_ptr这样的方式,Boost和C ++ 11标准也需要这个行为作为一个附加的灵活性shared_ptr管理不仅仅是一个引用计数器所谓的删除器通常放在同一个存储器块中,它也包含引用计数器,但有趣的部分是这个删除器的类型不是shared_ptr类型的一部分,这被称为类型擦除,并且基本上是用于为了使你的示例工作,我们需要一个模板化的构造函数:

  template< class T> 
class shared_ptr
{
public:
...
template< class Y>
explicit shared_ptr(Y * p);
...
};

所以,如果你使用这个与你的类Base和Derived ...

  class Base {}; 
class Derived:public Base {};

int main(){
shared_ptr< Base> sp(new Derived);
}

...带有Y = Derived的模板化构造函数用于构造shared_ptr目的。因此,构造函数有机会创建适当的删除对象和引用计数器,并将指向此控制块的指针存储为数据成员。如果引用计数器达到零,则先前创建的和Derived-aware删除器将用于处理对象。



C ++ 11标准有以下说法关于此构造函数(20.7.2.2.1):


需要: / code>必须可转换为 T * Y 应为完整类型。 表达式 delete p 应格式良好,应具有良好定义的行为,不得抛出异常



效果:构造 shared_ptr 对象拥有 > p



...


对于析构函数(20.7.2.2.2):


效果: use_count(< code))共享所有权。$ c> * )> 1 ),没有副作用。
否则,如果 *这个拥有一个对象 p 和一个删除 d d(p)
否则,如果 *这个拥有一个指针 p 删除p


p>

Mr. Lidström and me 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 to Derived, then unless Base 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? Thanks in advance

解决方案

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 or std::function for hiding the actual functor's type. To make your example work, we need a templated constructor:

template<class T>
class shared_ptr
{
public:
   ...
   template<class Y>
   explicit shared_ptr(Y* p);
   ...
};

So, if you use this with your classes Base and Derived ...

class Base {};
class Derived : public Base {};

int main() {
   shared_ptr<Base> sp (new Derived);
}

... the templated constructor with Y=Derived is used to construct the shared_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 and Derived-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):

Requires: p must be convertible to T*. Y shall be a complete type. The expression delete p shall be well formed, shall have well defined behaviour and shall not throw exceptions.

Effects: Constructs a shared_ptr object that owns the pointer p.

And for the destructor (20.7.2.2.2):

Effects: If *this is empty or shares ownership with another shared_ptr instance (use_count() > 1), there are no side effects. Otherwise, if *this owns an object p and a deleter d, d(p) is called. Otherwise, if *this owns a pointer p, and delete p is called.

(emphasis using bold font is mine).

这篇关于shared_ptr魔法:)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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