boost::weak_ptr和enable_shared_from_this

来源:互联网 发布:淘宝家具内容营销 编辑:程序博客网 时间:2024/05/20 23:34
 

boost::weak_ptr 和 enable_shared_from_this

 

shared_ptr 在我的实践中使用很广 , 在接口层面上 , 我基本都会默认的使用 shared_ptr. 而 weak_ptr 则很少使用 ; 即便使用 , 也是间接的使用 , 例如使得 class A 继承自boost::enable_shared_from_this, 这样 A 便具有了一个 weak_ptr 的成员对象 , 我便可以通过接口 shared_from_this() 得到一个 boost::shared_ptr<A> 的对象 .

除此之外 , 在实践中我几乎没有用到 weak_ptr. 到目前为止 , 我见到的对 weak_ptr 论述最好的是 << Beyond.the.C.plus.plus.Standard.Library.An.Introduction.to.Boost>>. 本书给出了使用 weak_ptr 的三种场景 : 打破递归的依赖关系 ; 使用一个共享的资源而不需要共享所有权 ; 避免悬空的指针 .

后面两种场景相对比较容易明白 , 对于第一种则相对模糊 . 最近几天我相对仔细的研究了一下 shared_ptr 和 weak_ptr 的源代码 , 给出我自己的理解如下 .

 

weak_ptr 是依附于 shared_ptr 的 , 所以首先要把 shared_ptr 弄清楚 ; 另外 , 我认为 boost::enable_shared_from_this 是解释递归的依赖关系的最好例子 , 所以使用这个实例解释weak_ptr 最好不过了 .

 

shared_ptr 的图解

 

 

 

 

    如图所示 ,3 个智能指针对象 sp1,sp2,sp3, 共享同一个对象 object 和同一个计数器 counter, 当 3 个指针对象 sp1,sp2,sp3 声明周期结束的时候 ,counter==0,object 会被销毁 ( 当然, 这个销毁器本身可以由你定制 ).

 

shared_ptr 的一个很大的特点是 :counter==0,object 会被销毁 ; 反之 , 如果 counter 总是不为 0, 那么 object 会成为永久对象 , 例如全局对象 .

 

在 http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/sp_techniques.html 中给出了一个从 this 获得 shared_ptr 的实例 , 答案是使用 weak_ptr, 问题是为什么是 weak_ptr.

 

让我们把这个问题重新说明一下 :

struct X

{

         boost::shared_ptr<X> getX()

{

         boost::shared_ptr<X> r ;//???? 如何实现

         return r;

}

};

 

要得到 X 的智能指针 , 只是在对象指针是受 shared_ptr 保护的基础上的 , 举例如下 :

void test_X()

{

         {

X x;

                  boost::shared_ptr<X> px = x.getX();// 错误

}

         {

X* x = new X();

boost::shared_ptr<X> px = x->getX();// 错误

}

         {

boost::shared_ptr<X>   x (new X());

boost::shared_ptr<X> px = x->getX();// 正确

}

}

我们再回到原来的问题上 , 如何实现 X::getX() 函数 . 要构造 X 的智能指针 , 需要知道两个信息 ,object 的指针和 object 的计数器 , 显然 , 指针本身可以通过 this 获得 , 问题是如何获得计数器 , 也即上面图中的 counter. 很显然 , 我们必须在 X 上存储某些信息来得到计数器 .

最先想到的也许是使用一个指向 counter 的指针存储在 X 上面 , 这样应该是可以的 , 但是存在一个问题 : 暴露了 shared_ptr 的实现细节 , 虽然 shared_ptr 是基于计数器的 , 但是这不属于用户需要知道的事情 . 最好的方式是让 shared_ptr 本身来充当这个角色 , 这样所有的实现细节就都封装在 shared_ptr 内部了 .

经过这样改装的 shared_ptr 的图解是 :

   

  

     经过这样包装的 object, 问题立刻暴露出来 : 循环引用 , 造成 object 对象无法释放 , 成为 ” 全局对象 ”. 很显然 , 问题在于 object 本身参与了引用计数 , 也就是所有权的分享 . 我们需要的是不同于 shared_ptr 的这样的一类共享指针 : 他们并不参与对象的所有权 , 只是能够观察到对象的所有权 . 而这正是 weak_ptr 的本质所在 .

 

当然了 ,weak_ptr 还有其他的特征 : 查看对象指针是否过期 ( 这也是比裸指针好的地方 ).

循环引用的情况很罕见 , 这可能也是我在实际中很少使用 weak_ptr 的原因吧 .

原创粉丝点击