weak_ptr 類模板
Introduction 簡介
Synopsis 概要
Members 成員
Free Functions 自由函數(shù)
Frequently Asked Questions 常見問題
weak_ptr 類模板存儲一個引向已被 shared_ptr 管理的對象的 "weak reference"(弱引用)。為了訪問這個對象,一個 weak_ptr 可以利用 shared_ptr 的構造函數(shù)或成員函數(shù) lock 轉換為 shared_ptr。當最后一個指向對象的 shared_ptr 消失,而對象也被刪除后,從一個引向已被刪除對象的 weak_ptr 實例獲取 shared_ptr 的企圖就會失敗:構造函數(shù)會拋出一個 boost::bad_weak_ptr 類型的異常,而 weak_ptr::lock 會返回一個 empty shared_ptr。
每一個 weak_ptr 都符合 C++ 標準庫的 CopyConstructible 和 Assignable 的必要條件,并因此能夠用于標準庫容器。因為提供了比較操作,因此 weak_ptr 可以和標準庫中的關聯(lián)式容器一起工作。
weak_ptr 的操作絕不會拋出異常。
這個類模板被 T 參數(shù)化,T 是被指向的對象的類型。
相對于 shared_ptr,weak_ptr 提供了一個非常有限的操作子集,因為在多線程程序中訪問它所存儲的指針是非常危險的,甚至有時在一個單線程程序中也是不安全的(也就是說,它可能引起未定義行為)。姑且假設 weak_ptr 有一個返回 raw pointer(裸指針)的 get 成員函數(shù),考慮下面這個無辜的代碼片段:
shared_ptr<int> p(new int(5)); weak_ptr<int> q(p);
// some time later
if(int * r = q.get()) { // use *r }
設想在 if 之后,但是又恰恰在 r 被使用之前,另一個線程執(zhí)行了語句 p.reset() 。這樣 r 就成了一個 dangling pointer(懸掛指針)。
解決這個問題的方案是從 q 創(chuàng)建一個臨時的 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 所指向的對象的引用。即使在其它線程中執(zhí)行了 p.reset() ,那個對象也會繼續(xù)活著,直到 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;
提供模板參數(shù) 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) 。
拋出:無。
注意:實現(xiàn)可以自由地經由不同的手段達到其效果(以及隱含的保證),而不創(chuàng)建臨時變量。
long use_count() const;
返回:如果 *this 為 empty,返回 0,否則,返回和 *this share ownership(共享所有權)的 shared_ptr 對象的數(shù)目。
拋出:無。
注意: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 對象在關聯(lián)式容器中作為鍵值使用。
template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b)
作用:等價于 a.swap(b) 。
拋出:無。
注意:與 std::swap 的接口匹配。為泛型編程提供幫助。
問:一個對象能不能在自己的構造函數(shù)內創(chuàng)建一個指向自己的 weak_ptr 呢?
答:不能。weak_ptr 只能從一個 shared_ptr 創(chuàng)建,而在對象構造的時候指向對象的 shared_ptr 還不存在。即使你能創(chuàng)建一個指向 this 的臨時 shared_ptr,它也會在構造函數(shù)結尾處離開作用域,而所有的 weak_ptr 實例立馬過期。
解決方案是把構造函數(shù)做成 private 的,并配備一個返回 shared_ptr 的工廠函數(shù)。
class X { private:
X();
public:
static shared_ptr<X> create() { shared_ptr<X> px(new X); // create weak pointers from px here return px; } };
|