引言

Understanding how deleters work in Boost’s shared_ptr, 2004. Boost’s reference-counting smart pointer shared_ptr has the interesting characteristic that you can pass it a function or function object during construction, and it will invoke this deleter on the pointed-to object when the reference count goes to zero.7 At first blush, this seems unremarkable, but look at the code:
template<typename T> class shared_ptr { public: template<typename U, typename D> explicit shared_ptr(U* ptr, D deleter); ... };
Notice that a shared_ptr<T> must somehow arrange for a deleter of type D to be invoked during destruction, yet the shared_ptr<T> has no idea what D is. The object can’t contain a data member of type D, nor can it point to an object of type D, because D isn’t known when the object’s data members are declared. So how can the shared_ptr object keep track of the deleter that will be passed in during construction and that must be used later when the T object is to be destroyed? More generally, how can a constructor communicate information of unknown type to the object it will be constructing, given that the object cannot contain anything referring to the type of the information?
The answer is simple: have the object contain a pointer to a base class of known type (Boost calls it sp_counted_base), have the constructor instantiate a template that derives from this base class using D as the instantiation argument (Boost uses the templates sp_counted_impl_p and sp_counted_impl_pd), and use a virtual function declared in the base class and defined in the derived class to invoke the deleter. (Boost uses dispose). Slightly simplified, it looks like this:

It’s obvious—once you’ve seen it. 8,9 But once you’ve seen it, you realize it can be used in all kinds of places, that it opens up new vistas for template design where templatized classes with relatively few template parameters (shared_ptr has only one) can reference unlimited amounts of information of types not known until later. Once I realized what was going on, I couldn’t help but smile and shake my head with admiration.10

来自 <http://www.artima.com/cppsource/top_cpp_aha_moments.html>

shared_ptr

在shared_ptr的实现中有一个地方个人觉得比较神奇:
先看shared_ptr的一般构造:


除了ptr成员指向保存的对象以外,ref_count也有一个ptr指向保存的对象,而shared_ptr在删除的时候其实是调用的delete ref_count.ptr,对于此的解释如下:
为什么图 1 中的 ref_count 也有指向 Foo 的指针?
shared_ptr<Foo> sp(new Foo) 在构造 sp 的时候捕获了 Foo 的析构行为。实际上 shared_ptr.ptr 和 ref_count.ptr 可以是不同的类型(只要它们之间存在隐式转换),这是 shared_ptr 的一大功能。分 3 点来说:
1. 无需虚析构;假设 Bar 是 Foo 的基类,但是 Bar 和 Foo 都没有虚析构。
shared_ptr<Foo> sp1(new Foo); // ref_count.ptr 的类型是 Foo*
shared_ptr<Bar> sp2 = sp1; // 可以赋值,自动向上转型(up-cast)
sp1.reset(); // 这时 Foo 对象的引用计数降为 1
此后 sp2 仍然能安全地管理 Foo 对象的生命期,并安全完整地释放 Foo,因为其 ref_count 记住了 Foo 的实际类型。
2. shared_ptr<void> 可以指向并安全地管理(析构或防止析构)任何对象;muduo::net::Channel class 的 tie() 函数就使用了这一特性,防止对象过早析构,见书 7.15.3 节。
shared_ptr<Foo> sp1(new Foo); // ref_count.ptr 的类型是 Foo*
shared_ptr<void> sp2 = sp1; // 可以赋值,Foo* 向 void* 自动转型
sp1.reset(); // 这时 Foo 对象的引用计数降为 1
此后 sp2 仍然能安全地管理 Foo 对象的生命期,并安全完整地释放 Foo,不会出现 delete void* 的情况,因为 delete 的是 ref_count.ptr,不是 sp2.ptr。
3. 多继承。假设 Bar 是 Foo 的多个基类之一,那么:
shared_ptr<Foo> sp1(new Foo);
shared_ptr<Bar> sp2 = sp1; // 这时 sp1.ptr 和 sp2.ptr 可能指向不同的地址,因为 Bar subobject 在 Foo object 中的 offset 可能不为0。
sp1.reset(); // 此时 Foo 对象的引用计数降为 1
但是 sp2 仍然能安全地管理 Foo 对象的生命期,并安全完整地释放 Foo,因为 delete 的不是 Bar*,而是原来的 Foo*。换句话说,sp2.ptr 和 ref_count.ptr 可能具有不同的值(当然它们的类型也不同)。

来自 <http://www.cppblog.com/Solstice/archive/2013/01/28/197597.html>

所以为题的重点在于ref_count.ptr如何保存真正的类型,比如:
class foo
{
};

class bar : public foo
{
};

std::shared_ptr<foo> p(new bar());

我们知道shared_ptr的定义:
template<class _Ty>
class shared_ptr
{ … }

如何在_Ty已经指定为foo的时候,保存一个类型为bar的成员变量呢?

这里我们用到了模板成员函数的自动推导:
template<class _Ux>
explicit shared_ptr(_Ux *_Px)
{… }
在构造的时候,我们通过自动推导,来以Ux表示真正的类型,在上面,Ux被推导为bar,接下来的问题是如何来保存Ux这个类型呢?

答案是在shared_ptr里保存一个_Ref_count_base的类型,在最上面的图中,ref_count就是此类型的一个指针变量:

class _Ref_count_base
{ // common code for reference counting
private:
virtual void _Destroy() = 0;
virtual void _Delete_this() = 0;

};

// TEMPLATE CLASS _Ref_count
template<class _Ty>
class _Ref_count
: public _Ref_count_base
{ // handle reference counting for object without deleter
public:
_Ref_count(_Ty *_Px)
: _Ref_count_base(), _Ptr(_Px)
{ // construct
}

private:
virtual void _Destroy()
{ // destroy managed resource
delete _Ptr;
}

virtual void _Delete_this()
{ // destroy self
delete this;
}

_Ty * _Ptr;
};

_Ref_count_base是不需要模板参数的,因此在shared_ptr里可以轻松的声明,而在shared_ptr构造函数里,我们可以实现:

ref_count = new _Ref_count<_Ux>(_Px); //ref_count:_Ref_count_base

这样我们就实现了保存真正类型的功能,在析构时,通过虚函数的调用,在delete ref_count的时候会调用子类里的delete操作,从而删除的是保存的指针真正的类型。

Boost::any

同样,在boost::any的实现也是如此,如何使用any在无模板参数指定的情况下保存任何类型呢,下面的实现和shared_ptr思想一致:
05.//自定义的any类   
06.class any   
07.{   
08.public:   
09.       
10.    //保存真正数据的接口类   
11.    class placeholder   
12.    {   
13.    public:        
14.        virtual ~placeholder()   
15.        {   
16.        }   
17.    public:    
18.  
19.        virtual const std::type_info & type() const = 0;   
20.        virtual placeholder * clone() const = 0;       
21.    };   
22.  
23.    //真正保存和获取数据的类。   
24.    template<typename ValueType>   
25.    class holder : public placeholder   
26.    {   
27.    public:            
28.        holder(const ValueType & value): held(value)   
29.        {   
30.        }   
31.  
32.    public:    
33.  
34.        virtual const std::type_info & type() const  
35.        {   
36.            return typeid(ValueType);   
37.        }   
38.  
39.        virtual placeholder * clone() const  
40.        {   
41.            return new holder(held);//使用了原型模式   
42.        }   
43.  
44.    public:    
45.  
46.        //真正的数据,就保存在这里   
47.        ValueType held;   
48.    };   
49.  
50.public:   
51.  
52.    any(): content(NULL)      
53.    {          
54.    }   
55.  
56.    //模板构造函数,参数可以是任意类型,真正的数据保存在content中   
57.    template<typename ValueType>   
58.    any(const ValueType & value): content(new holder<ValueType>(value))   
59.    {   
60.    }     
61.  
62.    //拷贝构造函数   
63.    any(const any & other)   
64.        : content(other.content ? other.content->clone() : 0)   
65.    {   
66.    }   
67.  
68.    //析构函数,删除保存数据的content对象   
69.    ~any()   
70.    {   
71.        if(NULL != content)   
72.            delete content;   
73.    }   
74.  
75.private:   
76.    //一个placeholde对象指针,指向其子类folder的一个实现   
77.    // 即content( new holder<ValueType>(value) )语句   
78.    placeholder* content;   
79.  
80.    template<typename ValueType> friend ValueType any_cast(const any& operand);   
81.public:    
82.  
83.    //查询真实数据的类型。   
84.    const std::type_info & type() const  
85.    {   
86.        return content ? content->type() : typeid(void);   
87.    }   
88.};

转载于:https://www.cnblogs.com/llluiop/p/6721150.html

Shared_ptr与 boost::any相关推荐

  1. boost智能指针之shared_ptr,scoped_ptr,intrusive_ptr,weak_ptr源码简析

    boost库实现了各种智能指针,基本上都纳入了c++11标准中,boost库的smart_ptr目录下就是各种指针的实现了: 1.shared_ptr template<class T> ...

  2. boost::shared_ptr文档翻译

    shared_ptr: 共享所有权 原文链接 描述 模版类 shared_ptr 存储动态构造对象的指针,通常是由C++ new语句完成的.这个对象指针在最后一个持有指针所有权的shared_ptr被 ...

  3. 有关智能指针(shared_ptr)的讨论

    1. boost::shared_ptr的用法2. boost::shared_ptr的实现机制3. 使用boost::shared_ptr的注意事项4. std::tr1::shared_ptr和b ...

  4. boost 库 enable_shared_from_this 实现原理分析

    使用情景:当类对象被 shared_ptr 管理时,需要在类自己定义的函数里把当前类对象作为参数传给其他函数时,这时需要传递一个 shared_ptr ,否则就不能保持 shared_ptr 管理这个 ...

  5. 【Boost】boost库中的小工具enable_shared_from_this

    使用情景: 当类对象被 shared_ptr 管理时,需要在类自己定义的函数里把当前类对象作为参数传给其他函数时,这时需要传递一个 shared_ptr ,否则就不能保持 shared_ptr 管理这 ...

  6. 【Boost】boost库中智能指针——intrusive_ptr

    boost::intrusive_ptr一种"侵入式"的引用计数指针,它实际并不提供引用计数功能,而是要求被存储的对象自己实现引用计数功能,并提供intrusive_ptr_add ...

  7. shared_ptr的一些尴尬

    http://blog.csdn.net/henan_lujun/article/details/8984543 shared_ptr在boost库中已经有多年了,C++11又为其正名,把他引入了ST ...

  8. 在你的代码中使用Boost智能指针

    在你的代码中使用Boost智能指针 Smart Pointers to boost your code(By peterchen)  翻译 masterlee Download source file ...

  9. bcp: 给boost瘦身

    bcp: 给boost瘦身 boost是一个非常优秀的库.问及多数C++程序员为什么最终没有选择Boost的原因,均回答:Boost太大,过于Heavy. 是的.这也是我多数在用与不用Boost之间徘 ...

最新文章

  1. springboot 简单自定义starter - beetl
  2. shell清除日志小脚本
  3. LINUX服务器开启防火墙并屏蔽恶意IP
  4. Tool之Adobe:解决Adobe acrobat pro将PDF文件进行批量保存单页PDF文件(图文教程)
  5. java 正则表达式 替换字符串img标签的路径_python面试题汇总第06期-正则表达式(内附7题及答案)...
  6. Qt 学习之路 2(80):定位器
  7. hbuilderx 小程序分包_基于uniapp的微信小程序之分包
  8. Be the Winner(结论:反nim博弈)
  9. php在线考试系统源代码_php实现在线考试系统
  10. 3.openldap生成LDAP用户
  11. 支持HomeKit、NFC:智汀智能门锁SL1仅需要149元
  12. 【活动更新】第一届Openbravo社区早餐会将与5/28在上海举办
  13. 【训练记录】2013-2014 Petrozavodsk Winter Training Camp, Moscow SU Trinity Contest @homework-7
  14. python打印什么意思,python语句:print(*[1,2,3]),是什么意思?
  15. 时钟容错同步算法之FTA
  16. Ubuntu下docker相关问题 - 持续更新中
  17. HTTP 204和304的区别
  18. win10+cuda9.2+cudnn 安装趟过的坑
  19. 机器学习之深入理解K最近邻分类算法(K Nearest Neighbor)
  20. 谨慎使用viewWithTag

热门文章

  1. android 文件mimetype_android文件关联之mime type
  2. 微博爬取显示全文_Python爬虫---chrome driver爬取微博(教你几十行代码爬取财宝宝微博长文)...
  3. 启动Eureka客户端服务时报错:java.net.ConnectException: Connection refused:connect
  4. 计算机网络知识大总结,包含各种熟悉得不能再熟悉的术语解析
  5. Android中文API(142) —— Gravity
  6. flex中list或Combox中的子项上移下移操作
  7. Open XML之我见
  8. python3.9新特性_Python 3.9正式版,新特性提前一睹为快
  9. 鼓励玩家自创,大量的UGC能为手游续命吗?
  10. java包含_【Java】判断字符串是否包含子字符串