weak_ptr类模版

最近在看陈硕的《Linux多线程服务端编程:使用muduo C++网络库》,第一章中重点讲了多线程下指针的处理问题,其中重点是 shared_ptr 与 weak_ptr, 上一篇博客学习了 shared_ptr 的基本用法 ( shared_ptr类模版 ),今天继续学习 weak_ptr ,以下是对 boost::weak_ptr 的中文翻译。

Introduction

weak_ptr 转化到 shared_ptr

weak_ptr 类模版存储了被 shared_ptr 管理的对象的“弱引用”,weak_ptr 能通过使用 shared_ptr 的构造函数 或者成员函数 转化到 shared_ptr。当最后一个指向对象的 shared_ptr 被销毁,对象会被销毁。weak_ptr 的对象被销毁后,试图从 weak_ptr 获得 shared_ptr 将失败,并且构造函数会抛出一个类型为 boost::bad_weak_ptr 的异常,weak_ptr::lock 将返回一个空的 shared_ptr。(?)

标准库

每一个 weak_ptr 都能拷贝构造和赋值,因而能用于标准库容器。另外,还有对比操作符,使得 weak_ptr 能用于标准库的关联容器。

操作

weak_ptr 操作符不抛出异常。

类模版使用 T 作为参数,T 为指向的对象类型。

与 shared_ptr 对比,weak_ptr 提供了非常有限的部分操作,因为在多线程程序里使用它存储的指针式通常是危险的,甚至在单线程中有时也不安全(也就是说,它会引起无定义的行为)。假设 weak_ptr 拥有一个 get 函数能够返回对象指针,如下面错误的代码:

1
2
3
4
5
6
7
8
9
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)指向已经销毁的对象或已经回收的地址,野指针(wild pointer)指的是 未经初始化的指针(http://en.wikipedia.org/wiki/Dangling_pointer)。

这个问题的解决办法是从 q 创建一个临时的 shared_ptr :

1
2
3
4
5
6
7
8
9
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,我们能够有效地锁定它防止销毁。

Synopsis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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);
}

Members

element_type

1
typedef T element_type;

提供模版参数 T 的类型

构造函数

1
weak_ptr();

效果:构建一个空的 weak_ptr 。
后置条件:use_count() == 0。
抛出:无。

1
2
3
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 是空的,构造一个空的 weak_ptr;否则,构造一个 weak_ptr 与 r 共享所有权,同时存储一份 r 中的指针的拷贝。
后置条件:use_count() == r.use_count()。
抛出:无。

析构函数

1
~weak_ptr();

效果:销毁这个 weak_ptr,但是对它保存的指针指向的对象无影响。
抛出:无。

赋值函数

1
2
3
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)。
抛出:无。

use_count

1
long use_count() const;

返回:如果*this为空,0;否则,与 weak_ptr 所共享所有权的 shared_ptr 的数目。
抛出:无。
注意:use_count() 不是高效的,只是用来调试和测试。

expired

1
bool expired() const;

返回:use_count() == 0。
抛出:无。
注意:expired() 比 use_count() 快。

lock

1
shared_ptr<T> lock() const;

返回:expired() ? shared_ptr< T >() : shared_ptr< T >(*this)。

reset

1
void reset();

效果:等价于 weak_ptr().swap(*this)。

swap

1
void swap(weak_ptr & b);

效果:交换两个智能指针的内容。
抛出:无。

Free Functions