auto_ptr,scoped_ptr,shared_ptr,weak_ptr

auto_ptr,scoped_ptr,shared_ptr,weak_ptr

auto_ptr的使用很简单,通过构造函数拥有一个动态分配对象的所有权,然后就可以被当作对象指针来使用,当auto_ptr对象被销毁的时候,它也会自动销毁自己拥有所有权的对象,release可以用来手动放弃所有权,reset可用于手动销毁内部对象。
但实际上,auto_ptr是一个相当容易被误用并且在实际中常常被误用的类。原因是由于它的对象所有权占用的特性和它非平凡的拷贝行为。
auto_ptr的对象所有权是独占性的!这决定了不可能有两个auto_ptr对象同时拥有同一动态对象的所有权,从而也导致了auto_ptr的拷贝行为是非对等的,其中伴随着对象所有权的转移。

同时也不要将auto_ptr放进标准库的容器中,否则在标准库容器无准备的拷贝行为中(标准库容器需要的拷贝行为是等价的),会导致难以发觉的错误。
auto_ptr特殊的拷贝行为使得使用它来远距离传递动态对象变成了一件十分危险的行为,在传递的过程中,一不小心就会留下一些实际为空但程序本身却缺少这样认知的auto_ptr对象。
简单的说来,auto_ptr适合用来管理生命周期比较短或者不会被远距离传递的动态对象,使用auto_ptr来管理动态分配对象,最好是局限于某个函数内部或者是某个类的内部。也就是说,动态对象的产生,使用和销毁的全过程是处于一个小的受控的范围,而不会在其中加入一些适应未来时态的扩展。
auto_ptr的几点注意事项:
1、auto_ptr不能共享所有权
2、auto_ptr不能指向数组
3、auto_ptr不能作为容器的成员
4、不能通过复制操作来初始化auto_ptr
std::auto_ptr<int> p(new int(42)); //OK
std::atuo_ptr<int>p = new int(42);//Error
这是因为auto_ptr的构造函数被定义了explicit

5、不要把auto_ptr放入容器

shared_ptr
shared_ptr的一个重要目的就是为了提供一个标准的共享所有权的智能指针。
shared_ptr就是为了解决auto_ptr在对象所有权上的局限性(auto_ptr是独占的),在使用引用计数的机制上提供了可以共享所有权的智能指针,当然这不会没有任何额外的代价……
 
首先一个shared_ptr对象除了包括一个所拥有对象的指针(px)外,还必须包括一个引用计数代理对象(shared_count)的指针(pn)。而这个引用计数代理对象包括一个真正的多态的引用计数对象(sp_counted_base)的指针(_pi),真正的引用计数对象在使用VC编译器的情况下包括一个虚表,一个虚表指针,和两个计数器。
假设我们有多个(5个以上)shared_ptr共享一个动态对象,那么每个shared_ptr的开销比起只使用原生指针的开销大概在3,4倍左右(这还是理想状况,忽略了动态分配带来的俑余开销)。如果只有一个shared_ptr独占动态对象,空间上开销更是高度十数倍!而auto_ptr的开销只是使用原生指针的两倍。
 
时间上的开销主要在初始化和拷贝操作上,*和->操作符重载的开销跟auto_ptr是一样的。
 
当然开销并不是我们不使用shared_ptr的理由,永远不要进行不成熟的优化,直到性能分析器告诉你这一点,这是Hurb提出的明智的建议。以上的说明只是为了让你了解强大的功能背后总是伴随着更多的开销,shared_ptr应该被使用,但是也不要过于滥用,特别是在一些auto_ptr更擅长的地方。
大多数成员函数都跟auto_ptr类似,但是没有了release(请看注释),reset用来放弃所拥有对象的所有权或拥有对象的变更,会引起原有对象的引用计数的减少。
shared_ptr是可以拷贝和赋值的,拷贝行为也是等价的,并且可以被比较,这意味这它可被放入标准库的一般容器(vector,list)和关联容器中(map)。

weak_ptr
weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象
weak_ptr的一个重要用途是通过lock获得this指针的shared_ptr,使对象自己能够生产shared_ptr来管理自己,但助手类enable_shared_from_this的shared_from_this会返回this的shared_ptr,只需要让想被shared_ptr管理的类从它继承即可
循环引用
引用计数是一种便利的内存管理机制,但它有一个很大的缺点,那就是不能管理循环引用的对象。
通过boost::weak_ptr来打破循环引用
由于弱引用不更改引用计数,类似普通指针,只要把循环引用的一方使用弱引用,即可解除循环引用。

由于在智能指针中保存的是指针的值而不是它们所指向的指针的值,因此在标准库容器中使用智能指针有一个常见的问题,就是如何在算法中使用智能指针;算法通常需要访问实际对象的值,而不是它们的地址。例如,你如何调用 std::sort 并正确地排序?实际上,这个问题与在容器中保存并操作普通指针是几乎一样的,但事实很容易被忽略(可能是由于我们总是避免在容器中保存裸指针)。当然我们不能直接比较两个智能指针的值,但也很容易解决。只要用一个解引用智能指针的谓词就可以了,所以我们将创建一个可重用的谓词,使得可以在标准库的算法里使用引向智能指针的迭代器,这里我们选用的智能指针是 weak_ptr。


scoped_ptr
boost::scoped_ptr 用于确保动态分配的对象能够被正确地删除。scoped_ptr 有着与std::auto_ptr类似的特性,而最大的区别在于它不能转让所有权而auto_ptr可以。事实上,scoped_ptr永远不能被复制或被赋值!scoped_ptr 拥有它所指向的资源的所有权,并永远不会放弃这个所有权。scoped_ptr的这种特性提升了我们的代码的表现,我们可以根据需要选择最合适的智能指针(scoped_ptr 或 auto_ptr)。

要决定使用std::auto_ptr还是boost::scoped_ptr, 就要考虑转移所有权是不是你想要的智能指针的一个特性。如果不是,就用scoped_ptr. 它是一种轻量级的智能指针;使用它不会使你的程序变大或变慢。它只会让你的代码更安全,更好维护。

scoped_ptr的用法与普通的指针没什么区别;最大的差别在于你不必再记得在指针上调用delete,还有复制是不允许的。典型的指针操作(operator* 和 operator->)都被重载了,并提供了和裸指针一样的语法。用scoped_ptr和用裸指针一样快,也没有大小上的增加,因此它们可以广泛使用。使用boost::scoped_ptr时,包含头文件"boost/scoped_ptr.hpp". 在声明一个scoped_ptr时,用被指物的类型来指定类模板的参数。例如,以下是一个包含std::string指针的scoped_ptr:

boost::scoped_ptr<std::string> p(new std::string("Hello"));

当scoped_ptr被销毁时,它对它所拥有的指针调用delete 。


scoped_ptr 不同于 const auto_ptr

留心的读者可能已经注意到auto_ptr可以几乎象scoped_ptr一样地工作,只要把auto_ptr声明为const:
const auto_ptr<A> no_transfer_of_ownership(new A);
它们很接近,但不是一样。最大的区别在于scoped_ptr可以被reset, 在需要时可以删除并替换被指物。而对于const auto_ptr这是不可能的const嘛。另一个小一点的区别是,它们的名字不同:尽管const auto_ptr意思上和scoped_ptr一样,但它更冗长,也更不明显。当你的词典里有了scoped_ptr,你就应该使用它,因为它可以更清楚地表明你的意图。如果你想说一个资源是要被限制在作用域里的,并且不应该有办法可以放弃它的所有权,你就应该用 boost::scoped_ptr.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值