weak_ptr 类模板
Introduction 简介
Synopsis 概要
Members 成员
Free Functions 自由函数
Frequently Asked Questions 常见问题
weak_ptr 类模板存储一个引向已被 shared_ptr 管理的对象的 "weak reference"(弱引用)。为了访问这个对象,一个 weak_ptr 可以利用 shared_ptr 的构造函数或成员函数 lock 转换为 shared_ptr。当最后一个指向对象的 shared_ptr 消失,而对象也被删除后,从一个引向已被删除对象的 weak_ptr 实例获取 shared_ptr 的企图就会失败:构造函数会抛出一个 boost::bad_weak_ptr 类型的异常,而 weak_ptr::lock 会返回一个 empty shared_ptr。
每一个 weak_ptr 都符合 C++ 标准库的 CopyConstructible 和 Assignable 的必要条件,并因此能够用于标准库容器。因为提供了比较操作,因此 weak_ptr 可以和标准库中的关联式容器一起工作。
weak_ptr 的操作绝不会抛出异常。
这个类模板被 T 参数化,T 是被指向的对象的类型。
相对于 shared_ptr,weak_ptr 提供了一个非常有限的操作子集,因为在多线程程序中访问它所存储的指针是非常危险的,甚至有时在一个单线程程序中也是不安全的(也就是说,它可能引起未定义行为)。姑且假设 weak_ptr 有一个返回 raw pointer(裸指针)的 get 成员函数,考虑下面这个无辜的代码片段:
shared_ptr<int> p(new int(5)); weak_ptr<int> q(p);
// some time later
if(int * r = q.get()) { // use *r }
设想在 if 之后,但是又恰恰在 r 被使用之前,另一个线程执行了语句 p.reset() 。这样 r 就成了一个 dangling pointer(悬挂指针)。
解决这个问题的方案是从 q 创建一个临时的 shared_ptr:
shared_ptr<int> p(new int(5)); weak_ptr<int> q(p);
// some time later
if(shared_ptr<int> r = q.lock()) { // use *r }
这样,r 就持有一个引向 q 所指向的对象的引用。即使在其它线程中执行了 p.reset() ,那个对象也会继续活着,直到 r 离开作用域或者被 reset。通过获得一个指向这个对象的 shared_ptr,我们可以有效地保住它不被析构。
namespace boost {
template<class T> class weak_ptr {
public: typedef T element_type;
weak_ptr();
template<class Y> weak_ptr(shared_ptr<Y> const & r); weak_ptr(weak_ptr const & r); template<class Y> weak_ptr(weak_ptr<Y> const & r);
~weak_ptr();
weak_ptr & operator=(weak_ptr const & r); template<class Y> weak_ptr & operator=(weak_ptr<Y> const & r); template<class Y> weak_ptr & operator=(shared_ptr<Y> const & r);
long use_count() const; bool expired() const; shared_ptr<T> lock() const;
void reset(); void swap(weak_ptr<T> & b); };
template<class T, class U> bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b);
template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b); }
typedef T element_type;
提供模板参数 T 的类型。
weak_ptr();
作用:构造一个 empty weak_ptr。
后置条件:use_count() == 0 。
抛出:无。
template<class Y> weak_ptr(shared_ptr<Y> const & r); weak_ptr(weak_ptr const & r); template<class Y> weak_ptr(weak_ptr<Y> const & r);
作用:如果 r 为 empty,构造一个 empty weak_ptr,否则,构造一个和 r shares ownership(共享所有权)的 weak_ptr,就像存储了 r 中所存储指针的一个拷贝。
后置条件:use_count() == r.use_count() 。
抛出:无。
~weak_ptr();
作用:销毁这个 weak_ptr,但对于所存储指针所指向的对象没有作用。
抛出:无。
weak_ptr & operator=(weak_ptr const & r); template<class Y> weak_ptr & operator=(weak_ptr<Y> const & r); template<class Y> weak_ptr & operator=(shared_ptr<Y> const & r);
作用:等价于 weak_ptr(r).swap(*this) 。
抛出:无。
注意:实现可以自由地经由不同的手段达到其效果(以及隐含的保证),而不创建临时变量。
long use_count() const;
返回:如果 *this 为 empty,返回 0,否则,返回和 *this share ownership(共享所有权)的 shared_ptr 对象的数目。
抛出:无。
注意:use_count() 达不到必要的效率。只用于调试和测试的目的。而不要用于产品代码。
bool expired() const;
返回:use_count() == 0 。
抛出:无。
注意:expired() 可能比 use_count() 更快。
shared_ptr<T> lock() const;
返回:expired()? shared_ptr<T>(): shared_ptr<T>(*this) 。
抛出:无。
void reset();
作用:等价于 weak_ptr().swap(*this) 。
void swap(weak_ptr & b);
作用:交换两个智能指针的内容。
抛出:无。
template<class T, class U> bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b);
返回:一个未确定值,以致于
-
operator< 是一个严格意义上的 C++ 标准 25.3
[lib.alg.sorting] 中描述的 weak ordering(弱顺序);
-
等值关系通过 operator< 来定义,
!(a < b) && !(b < a) ,在这种情况下,当且仅当两个 weak_ptr 实例 share ownership(共享所有权)或者都为 empty 时,两个 weak_ptr 相等。
抛出:无。
注意:允许 weak_ptr 对象在关联式容器中作为键值使用。
template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b)
作用:等价于 a.swap(b) 。
抛出:无。
注意:与 std::swap 的接口匹配。为泛型编程提供帮助。
问:一个对象能不能在自己的构造函数内创建一个指向自己的 weak_ptr 呢?
答:不能。weak_ptr 只能从一个 shared_ptr 创建,而在对象构造的时候指向对象的 shared_ptr 还不存在。即使你能创建一个指向 this 的临时 shared_ptr,它也会在构造函数结尾处离开作用域,而所有的 weak_ptr 实例立马过期。
解决方案是把构造函数做成 private 的,并配备一个返回 shared_ptr 的工厂函数。
class X { private:
X();
public:
static shared_ptr<X> create() { shared_ptr<X> px(new X); // create weak pointers from px here return px; } };
|