weak_ptr
class templateIntroduction
Synopsis
Members
Free Functions
Frequently Asked Questions
weak_ptr クラステンプレートは、既に shared_ptr により管理されているオブジェクトへの "弱参照" を保持する。 shared_ptr のコンストラクタ を利用して weak_ptr を shared_ptr に変換するか、 メンバ関数 lock を使うことで、 保持しているオブジェクトにアクセスできる。 所有権を共有している最後の shared_ptr が破棄され、 保持しているオブジェクトが削除された場合、 その削除済みのオブジェクトを参照する weak_ptr インスタンスを shared_ptr へと変換する試みが失敗する: 変換コンストラクタは boost::bad_weak_ptr 例外を送出し、 weak_ptr::lock は空の shared_ptr を返す。
weak_ptr は C++標準ライブラリのコピーコンストラクト可能(CopyConstructible) および代入可能(Assignable)の要求を満たしているので、 標準ライブラリコンテナに格納することができる。 また、比較演算子が提供されているので標準の連想コンテナに格納することができる。
weak_ptr の命令は例外を送出しない。
このクラステンプレートには、指し示すオブジェクトの型を表すパラメータ T を与える。
weak_ptr に保持されているポインタへのアクセスは マルチスレッドプログラムにおいてしばしば危険にさらされるため、 weak_ptr が提供する命令は shared_ptr が提供する命令と比較して、 制限が大幅に強化されたサブセットとなっている。 また、シングルスレッドプログラムにおいても、安全と言い切れない場面がある (それは未定義のふるまいを引き起こす)。 ここで、weak_ptr に生ポインタを返すメンバ関数 get() があるとして、次の悪意のないコードについて考えてみよう:
shared_ptr<int> p(new int(5)); weak_ptr<int> q(p);
// その少し後で
if(int * r = q.get())
{
// *r を使う }
if の後、且つ r
が使われる直前に、別のスレッドが p.reset()
という文を実行することを考えてみよう。
その時点で、r はダングリングポインタになってしまう
(※訳注:ダングリングポインタ(dangling pointer)とは、何を指しているかわからないポインタのこと)
この問題を解決する方法は、q から一時的な shared_ptr を作成することである:
shared_ptr<int> p(new int(5)); weak_ptr<int> q(p);
// その少し後で
if(shared_ptr<int> r = q.lock())
{
// *r を使う }
ここでは、r は q に指されたオブジェクトを参照している。
もし p.reset() が別のスレッドで実行されても、参照されているオブジェクトは
r がスコープを抜けるかリセットされるまで生存し続ける。
そのオブジェクトを指す 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();
Effects: 空(empty)の weak_ptr を構築する。
Postconditions:
use_count() == 0Throws: 無し。
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);
Effects: もし r が空(empty)ならば、 空(empty)の weak_ptr を構築する; そうでなければ、まるで r が持つポインタのコピーを持ち合う様に r と所有権を共有する weak_ptr を構築する。
Postconditions:
use_count() == r.use_count()Throws: 無し。
~weak_ptr();
Effects: その weak_ptr を破棄する。 指されているオブジェクトには何も作用を及ぼさない。
Throws: 無し。
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);
Effects:
weak_ptr(r).swap(*this)と等価。Throws: 無し。
Notes: 実際の実装は、上記とは異なる表現により、 一時オブジェクトを作成せずに上記のコードと同様の作用(effects)と保証を得る。
long use_count() const;
Returns: もし *this が空(empty)ならば、 不特定の非負の数; そうでなければ、*this と所有権を共有する shared_ptr オブジェクトの数。
Throws: 無し。
Notes:
use_count()は必ずしも効率的なものではない。 デバッグやテスト目的でのみ使い、製品のコードには使わないこと。
bool expired() const;
Returns:
use_count() == 0Throws: 無し。
Notes:
expired()はuse_count()よりも速いかもしれない。
shared_ptr<T> lock() const;
Returns:
expired()? shared_ptr<T>(): shared_ptr<T>(*this).Throws: 無し。
void reset();
Effects:
weak_ptr().swap(*this)と等価。
void swap(weak_ptr & b);
Effects: 二つのスマートポインタの内容を入れ替える。
Throws: 無し。
template<class T, class U> bool operator<(weak_ptr<T> const & a, weak_ptr<U> const & b);
Returns: 以下に示すような明示的でない値。
- C++標準の 25.3 章
[lib.alg.sorting]で述べられているように、 operator< の演算子結合順位は極めて低い;- operator< により定義される等価関係
!(a < b) && !(b < a)は、 二つの weak_ptr インスタンスが 所有権を共有しているとき に限り成り立つ。Throws: 無し。
Notes: weak_ptr オブジェクトを連想コンテナのキーとして使えるようにするための演算子。
template<class T> void swap(weak_ptr<T> & a, weak_ptr<T> & b)
Effects:
a.swap(b)と等価。Throws: 無し。
Notes: std::swap とのインターフェースの共通化を図り、 ジェネリックプログラミングを支援する。
Q. コンストラクタの中で、自身を指す weak_ptr を作成するオブジェクトを作れますか?
A. いいえ、できません。 weak_ptr は shared_ptr からのみ作成する事ができるのですが、オブジェクトを構築する時点では、そのオブジェクトを指す shared_ptr はまだ存在しないでしょう。 例え this を指す一時的な shared_ptr を作成したとしても、コンストラクタのスコープを抜けた時点でその shared_ptr インスタンスは破棄されてしまい、 全ての weak_ptr インスタンスは即座に期限切れ(expire)になってしまいます。
この質問に対する解決策は、コンストラクタをプライベートにし、
shared_ptr
を返すファクトリ関数を提供することです:
class X
{
private:
X();
public:
static shared_ptr<X> create()
{
shared_ptr<X> px(new X);
// ここで px から弱参照ポインタ(weak_ptr)を作成する
return px;
}
};
$Date: 2003/09/02 06:19:54 $
Copyright 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. Copyright 2002, 2003 Peter Dimov. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.
Japanese Translation Copyright (C) 2003
Ryo Kobayashi,
Kohske Takahashi.
オリジナルの、及びこの著作権表示が全ての複製の中に現れる限り、この文書の
複製、利用、変更、販売そして配布を認める。このドキュメントは「あるがまま」
に提供されており、いかなる明示的、暗黙的保証も行わない。また、
いかなる目的に対しても、その利用が適していることを関知しない。