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; //译注:原文是unspecified-bool-type(),有误 void swap(shared_ptr<T>& b); }; template <class T,class U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r); }
template <class Y> explicit shared_ptr(Y* p);
这个构造函数获得给定指针p的所有权。参数 p 必须是指向 Y 的有效指针。构造后引用计数设为1。唯一从这个构造函数抛出的异常是std::bad_alloc (仅在一种很罕见的情况下发生,即不能获得引用计数器所需的自由空间)。
template <class Y,class D> shared_ptr(Y* p,D d);
这个构造函数带有两个参数。第一个是shared_ptr将要获得所有权的那个资源,第二个是shared_ptr被销毁时负责释放资源的一个对象,被保存的资源将以d(p)的形式传给那个对象。因此p的值是否有效取决于d。如果引用计数器不能分配成功,shared_ptr抛出一个类型为std::bad_alloc的异常。
shared_ptr(const shared_ptr& r);
r中保存的资源被新构造的shared_ptr所共享,引用计数加一。这个构造函数不会抛出异常。
template <class Y> explicit shared_ptr(const weak_ptr<Y>& r);
从一个weak_ptr (本章稍后会介绍)构造shared_ptr。这使得weak_ptr的使用具有线程安全性,因为指向weak_ptr参数的共享资源的引用计数将会自增(weak_ptr不影响共享资源的引用计数)。如果weak_ptr为空 (r.use_count()==0), shared_ptr 抛出一个类型为bad_weak_ptr的异常。
template <typename Y> shared_ptr(std::auto_ptr<Y>& r);
这个构造函数从一个auto_ptr获取r中保存的指针的所有权,方法是保存指针的一份拷贝并对auto_ptr调用release。构造后的引用计数为1。而r当然就变为空的。如果引用计数器不能分配成功,则抛出 std::bad_alloc 。
~shared_ptr();
shared_ptr析构函数对引用计数减一。如果计数为零,则保存的指针被删除。删除指针的方法是调用operator delete 或者,如果给定了一个执行删除操作的客户化删除器对象,就把保存的指针作为唯一参数调用这个对象。析构函数不会抛出异常。
shared_ptr& operator=(const shared_ptr& r);
赋值操作共享r中的资源,并停止对原有资源的共享。赋值操作不会抛出异常。
void reset();
reset函数用于停止对保存指针的所有权的共享。共享资源的引用计数减一。
T& operator*() const;
这个操作符返回对已存指针所指向的对象的一个引用。如果指针为空,调用operator* 会导致未定义行为。这个操作符不会抛出异常。
T* operator->() const;
这个操作符返回保存的指针。这个操作符与operator*一起使得智能指针看起来象普通指针。这个操作符不会抛出异常。
T* get() const;
get函数是当保存的指针有可能为空时(这时 operator* 和 operator-> 都会导致未定义行为)获取它的最好办法。注意,你也可以使用隐式布尔类型转换来测试 shared_ptr 是否包含有效指针。这个函数不会抛出异常。
bool unique() const;
这个函数在shared_ptr是它所保存指针的唯一拥有者时返回 true ;否则返回 false。 unique 不会抛出异常。
long use_count() const;
use_count 函数返回指针的引用计数。它在调试的时候特别有用,因为它可以在程序执行的关键点获得引用计数的快照。小心地使用它,因为在某些可能的shared_ptr实现中,计算引用计数可能是昂贵的,甚至是不行的。这个函数不会抛出异常。
operator unspecified-bool-type() const;
这是个到unspecified-bool-type类型的隐式转换函数,它可以在Boolean上下文中测试一个智能指针。如果shared_ptr保存着一个有效的指针,返回值为True;否则为false。注意,转换函数返回的类型是不确定的。把返回类型当成bool用会导致一些荒谬的操作,所以典型的实现采用了safe bool idiom,它很好地确保了只有可适用的Boolean测试可以使用。这个函数不会抛出异常。
void swap(shared_ptr<T>& b);
这可以很方便地交换两个shared_ptr。swap 函数交换保存的指针(以及它们的引用计数)。这个函数不会抛出异常。
普通函数
template <typename T,typename U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);
要对保存在shared_ptr里的指针执行static_cast,我们可以取出指针然后强制转换它,但我们不能把它存到另一个shared_ptr里;新的 shared_ptr 会认为它是第一个管理这些资源的。解决的方法是用 static_pointer_cast. 使用这个函数可以确保被指物的引用计数保持正确。static_pointer_cast 不会抛出异常。
用法
使用shared_ptr解决的主要问题是知道删除一个被多个客户共享的资源的正确时机。下面是一个简单易懂的例子,有两个类 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); }类 A 和 B都保存了一个 shared_ptr<int>. 在创建 A 和 B的实例时,shared_ptr temp 被传送到它们的构造函数。这意味着共有三个 shared_ptr:a, b, 和 temp,它们都引向同一个int实例。如果我们用指针来实现对一个的共享,A 和 B 必须能够在某个时间指出这个int要被删除。在这个例子中,直到main的结束,引用计数为3,当所有 shared_ptr离开了作用域,计数将达到0,而最后一个智能指针将负责删除共享的 int.
#include "boost/shared_ptr.hpp" #include <vector> #include <iostream> class A { public: virtual void sing()=0; protected: virtual ~A() {}; }; class B : public A { public: virtual void sing() { std::cout << "Do re mi fa so la"; } }; boost::shared_ptr<A> createA() { boost::shared_ptr<A> p(new B()); return p; } int main() { typedef std::vector<boost::shared_ptr<A> > container_type; typedef container_type::iterator iterator; container_type container; for (int i=0;i<10;++i) { container.push_back(createA()); } std::cout << "The choir is gathered: \n"; iterator end=container.end(); for (iterator it=container.begin();it!=end;++it) { (*it)->sing(); } }
class FileCloser { public: void operator()(FILE* file) { std::cout << "The FileCloser has been called with a FILE*, " "which will now be closed.\n"; if (file!=0) fclose(file); } };
int main() { std::cout << "shared_ptr example with a custom deallocator.\n"; { FILE* f=fopen("test.txt","r"); if (f==0) { std::cout << "Unable to open file\n"; throw "Unable to open file"; } boost::shared_ptr<FILE> my_shared_file(f, FileCloser()); // 定位文件指针 fseek(my_shared_file.get(),42,SEEK_SET); } std::cout << "By now, the FILE has been closed!\n"; }
{ FILE* f=fopen("test.txt","r"); if (f==0) { std::cout << "Unable to open file\n"; throw file_exception(); } boost::shared_ptr<FILE> my_shared_file(f,&fclose); // 定位文件指针 fseek(&*my_shared_file,42,SEEK_SET); } std::cout << "By now, the FILE* has been closed!\n";
#include "boost/shared_ptr.hpp" #include <iostream> class A { class deleter { public: void operator()(A* p) { delete p; } }; friend class deleter; public: virtual void sing() { std::cout << "Lalalalalalalalalalala"; } static boost::shared_ptr<A> createA() { boost::shared_ptr<A> p(new A(),A::deleter()); return p; } protected: virtual ~A() {}; }; int main() { boost::shared_ptr<A> p=A::createA(); }
#include "boost/shared_ptr.hpp" #include "boost/enable_shared_from_this.hpp" class A; void do_stuff(boost::shared_ptr<A> p) { ... } class A : public boost::enable_shared_from_this<A> { public: void call_do_stuff() { do_stuff(shared_from_this()); } }; int main() { boost::shared_ptr<A> p(new A()); p->call_do_stuff(); }