shared_ptr
Header: "boost/shared_ptr.hpp"
几乎全部有效程序都需要一些引用记数(reference-counted)形式的智能指针.这些只能指针使我们不再需要自己写复杂的逻辑来控制被共享对象的生命期.当引用记数降到0,没有对象对这个被共享对象感兴趣,所以它自动delete.引用记数智能指针被分类为侵入式和非侵入式.类格式提供一个确定的功能函数或者数据成员来管理引用记数.那意味着设计类带有预见性的可以与侵入式,引用记数智能指针类,或者改进型共同工作.非侵入式,引用记数智能指针不需要管理任何类型.引用记数智能指针假设内存的所有权与存储他们的指针相关联.在没有智能指针帮助下使用共享对象的问题是必须有人最终delete共享内存.谁做,何时做?没有引用记数智能指针,一个外部的生命期管理必须强加于被管理的内存,它典型的表达了所有权集合之间存在很强的互相依附关系.那样妨碍了可重用性和增加了复杂度.
被管理的类或许有一个属性使它能成为一个优秀的候选来和引用记数智能指针一起使用.比如,事实上,它复制开销很大,或者它表示需要被多个实例共享,合理的共享所有权.还有的情况不存在一个明确的共享资源拥有者.应用引用记数智能指针使需要在对象间分享一个共享资源成为可能.同样在标准库中使没有危险和没有泄露的条件下存储对象指针成为可能,尤其面对异常时或者当从容器中移除元素时.当你在容器中存储指针时,你能得到多态的优势,效率改良(如果复制需要很大花费的话),还具备存储多个相同对象的能力,关联容器的专门检查.
在你有理由并决定使用引用记数智能指针后,怎样选择使用侵入式还是非侵入式的设计?非侵入式
几乎总是较好的选择因为它的一般适用性,对现存代码影响少,灵活.你可以使用非侵入式,引用记数智能指针对那些你希望保持不变的类.通常的方法是改编一个类来和侵入式的一起工作,引用记数智能指针是从引用记数基类派生出来的.乍一看它的变化或许伴随着更多的开销.但是至少,它增加了相互依存关系和加强了可重用性.它同样增加了对象大小,或在一些范围内限制了可用性.
一个shared_ptr可以由原生指针,另一个shared_ptr,一个std::auto_ptr,或者一个boost::weak_ptr创建.它同样可以传递第二个实参到shared_ptr的constructor,当做释放者.
它会被最后调用来释放被共享资源.这是非常有用的对于管理那些不是通过new分配和delete销毁的资源(我们稍后将看到一些创建用户释放者的例子).shared_ptr被创建后,它会被像普通指针一样的使用,没有被明确删除的情况下回显示异常.
这是shared_ptr的一个部分纲要;最重要的成员和自由函数被列出来,随后将简短的讨论.
namespace boost {
template<typename T> class shared_ptr {
public:
template <class Y> explicit shared_ptr(Y* p);
template <class Y,class D> shared_ptr(Y* p,D d);
~shared_ptr();
shared_ptr(const shared_ptr & r);
template <class Y> explicit
shared_ptr(const weak_ptr<Y>& r);
template <class Y> explicit shared_ptr(std::auto_ptr<Y>& r);
shared_ptr& operator=(const shared_ptr& r);
void reset();
T& operator*() const;
T* operator->() const;
T* get() const;
bool unique() const;
long use_count() const;
operator unspecified-bool-type() const;
void swap(shared_ptr<T>& b);
};
template <class T,class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);
}
Members
template <class Y> explicit shared_ptr(Y* p);
这个constructor接管参数指针p的所有权.失参p必须是一个有效的Y的指针.创建后引用记数被设为1.仅当constructor为std::bad_alloc时抛出异常(它仅在引用记数没分配真种不太可能的情况下发生).
template <class Y,class D> shared_ptr(Y* p,D d);
此constructor有俩个参数.第一个是shared_ptr接管所有权的资源,第二个是负责释放资源的对象当shared_ptr被销毁.被存储的资源被传递给对象以d(p).p的有效值取决于d.如果reference counter不能被分配,shared_ptr抛出std::bad_alloc类型的异常.
shared_ptr(const shared_ptr& r);
在r中被存储资源通过创建shared_ptr对象被分享,reference count加1.这个copy constructor不抛出异常.
template <class Y> explicit shared_ptr(const weak_ptr<Y>& r);
从weak_ptr(在本章后面介绍)创建一个shared_ptr.它使weak_ptr具有thread-safe的用处,因为被共享资源的reference count将通过weak_ptr的参数自增(weak_ptr不会影响被共享资源的reference count).如果weak_ptr是空的话(r.use_count()==0),shared_ptr抛出bad_weak_ptr类型的异常.
template <typename Y> shared_ptr(std::auto_ptr<Y>& r);
这个construction从auto_ptr接过r存储对象的所有权通过存储一个指针副本并释放原auto_ptr.创建后reference count是1.代表r,当然,耗尽内存的情况下,reference counter无法分配将抛出std::bad_alloc
~shared_ptr();
shared_ptr的destructor减少reference count 1.如果count为0,被指资源delete.delete指针将通过调用operator delete或者使用用户提供的释放者对象来销毁,此对象将被存储的指针作为它的唯一参数调用.destructor不抛出异常.
shared_ptr& operator=(const shared_ptr& r);
copy assignment operator共享r中的资源并停止共享当前被共享的资源.此copy assignment operator不抛出异常
void reset();
此函数被用于停止共享被存储指针的所有权.被共享资源的reference count变0.
T& operator*() const;
此operator返回一个被存储指针所指向对象的引用,如果指针为null,operator*导致未定义行为.此operator不抛出异常
T* operator->() const;
此operator返回被存储的指针.同operator*一起使smart pointer看起来想普通指针.此operator不抛出异常
T* get() const;
get function是检查被存储指针是否为null的首选方法(在null情形下operator* and operator->导致为定义行为).注意它同样可以测试一个shared_ptr是否包含一个有效指针通过使用暗式Boolean类型转换.此function不抛出异常.
bool unique() const;
此函数返回true当shared_ptr是被存储指针的唯一拥有者;否则,返回false.unique不抛出异常.
long use_count() const;
此函数返回指针的reference count.在调试用途中尤其有用,因为他能被用来获得reference count的简短信息在执行程序的关键点处.保守的使用它.为了使一些shared_ptr的接口可以执行,计算reference count也许有很大开销甚至是不可能的.此函数不抛出异常.
operator unspecified-bool-type() const;
它暗式转换为一个类型,unspecified-bool-type,使用Boolean来测试一个smart pointer成为可能.如果当前存储一个有效指针则为true,否则,则为false.此转换函数返回的类型是为规定的.使用bool作为返回类型将允许一些无意义的操作,代表性的,使用safe bool idiom来实现,的确是一个漂亮的办法来确保仅当适当的逻辑测试才能被使用.此函数不抛出异常.
void swap(shared_ptr<T>& b);
它有时方便的交换俩个shared_ptrs的内容.swap函数交换被存储的指针(和它们的reference counts).此函数不抛出异常.
Free Functions
template <typename T,typename U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);
执行一个static_cast从被存储的指针到shared_ptr,我们可以检查指针然后转换它,但是我们不能存储它在另外一个shared_ptr中;新的shared_ptr将认为它是指针关联的资源的第一个管理者.它可以被补救通过static_pointer_cast.使用这个函数确保指针剩余的reference count不变性.static_pointer_cast不抛出异常.
Usage
shared_ptr解决的主要问题是在正确是时间delete被多个用户共享的资源.这里有个直观的例子,
有俩个classes, A和B,共享一个int实例.使用boost::shared_ptr,你需要包含"boost/shared_ptr.hpp".
#include "boost/shared_ptr.hpp"
#include <cassert>
class A {
boost::shared_ptr<int> no_;
public:
A(boost::shared_ptr<int> no) : no_(no) {}
void value(int i) {
*no_=i;
}
};
class B {
boost::shared_ptr<int> no_;
public:
B(boost::shared_ptr<int> no) : no_(no) {}
int value() const {
return *no_;
}
};
int main() {
boost::shared_ptr<int> temp(new int(14));
A a(temp);
B b(temp);
a.value(28);
assert(b.value()==28);
}
classes A和B都存储一个shared_ptr<int>.当创造A和B的实例时,shared_ptr temp被传递进了他们的constructor.这以为着这三个shared_ptr,a,b,和temp现在引用一个共同的int实例.我们用指针达到了分享一个int的目的,A和B将计算出它应该在何时被delete.在本例中,reference count是3直到main的结束,所有的shared_ptr跳出作用域,减少count知道为0,允许最后一个smart pointers来delete共享的int.