OSDN Git Service

memberwise_swap を追加
[gintenlib/gintenlib.git] / gintenlib / to_shared.hpp
1 #ifndef GINTENLIB_INCLUDED_TO_SHARED_HPP_
2 #define GINTENLIB_INCLUDED_TO_SHARED_HPP_
3
4 /*
5
6       <gintenlib/to_shared.hpp>
7
8   to_shared : 任意のポインタを shared_ptr に変換
9
10   宣言:
11     // 任意ポインタ
12     template<typename P>
13     shared_ptr<typename P::element_type> to_shared( const P& pt );
14     
15     // std::auto_ptr
16     template<typename T>
17     shared_ptr<T> to_shared( std::auto_ptr<T> p );
18     
19     // trivial ですが shared_ptr からも
20     template<typename T>
21     shared_ptr<T> to_shared( const shared_ptr<T>& p );
22     
23     // これは intrusive_to_shared.hpp 内で定義
24     template<typename T>
25     shared_ptr<T> to_shared( const boost::intrusive_ptr<T>& p );
26     
27     // そのほか、銀天ライブラリの各スマートポインタに対し適切な to_shared が定義されている
28
29   機能:
30     各種スマートポインタを shared_ptr に変換します。
31     名前空間の自動紹介は行わない事になりました。代わりに using gintenlib::to_shared としてください。
32
33 */
34
35 #include "shared_ptr.hpp"
36 #include "intrusive_to_shared.hpp"
37
38 #include <cassert>
39 #include <memory>
40
41 namespace gintenlib
42 {
43   // std::auto_ptr version
44   // 実際のところ必要ないけど
45   template<typename T>
46   inline shared_ptr<T> to_shared( std::auto_ptr<T> pt )
47   {
48     return shared_ptr<T>( pt.release() );
49   }
50   
51   // trivial version
52   template<typename T>
53   inline shared_ptr<T> to_shared( const shared_ptr<T>& pt )
54   {
55     return pt;
56   }
57
58   // 汎用バージョン
59   
60   // いわゆる「スマートポインタ」を保持するホルダ
61   // shared_ptr のコンストラクタの第二引数として渡す削除子として使える
62   template<typename Pointer>
63   struct to_shared_holder
64   {
65     typedef typename Pointer::element_type T;
66     typedef shared_ptr<T> shared_t;
67     
68     // 構築
69     to_shared_holder()
70       : pt() {}
71     to_shared_holder( const Pointer& pt_ )
72       : pt( pt_ ) {}
73     
74     // shared_ptr にする
75     static shared_t to_shared( const Pointer& pt_ )
76     {
77       // まず null pointer に対する最適化
78       T* p = pt_.get();
79       if( !p ){ return shared_t(); }
80       
81       // 本体は転送
82       return to_shared_holder(pt_).to_shared();
83     }
84     // 本体
85     // これを実行すると、このオブジェクトは NULL に再設定される
86     shared_t to_shared()
87     {
88       using namespace std;  // for assert()
89       T* p = pt.get();
90       
91       // いったん仮の to_shared_holder を使って shared_ptr を作る
92       // ここで例外が投げられた場合、何も行われず抜けるので安全
93       shared_t temp( p, to_shared_holder() );
94       
95       // 作られた shared_ptr の中身をいじる
96       // ポイントは、ここから仮の to_shared_holder が正しく設定されるまで、例外が投げられないこと
97       
98       // これは例外を投げない
99       to_shared_holder* holder = boost::get_deleter< to_shared_holder >( temp );
100       // 作ったばかりの holder の型が不一致なわけない
101       assert( holder != 0 );
102       
103       // これも大丈夫
104       Pointer& pt_ = holder->pt;
105       // これが一番の山場。普通は swap は nothrow と信じる
106       swap( pt, pt_ );
107       
108       // これで to_shared_pointer の中身が正しく設定された
109       
110       // 一応確認する
111       assert( pt.get() == 0 && pt_.get() == p );
112       
113       // 何故こんな面倒なことをしているかというと、
114       // 深いコピーを行うタイプのスマートポインタも問題なく保持できるようにしたいため。
115       // Pointer p2 = p1; の処理をした後に、 p1.get() == p2.get() である保証はないのです
116       
117       // 完成した shared_ptr を返す
118       return temp;
119     }
120     
121     // 一番大事なはずの削除関数・・・だが
122     // やってることは特に無し
123     typedef void result_type;
124     void operator()( T* target ) throw ()
125     {
126       // 一応、正しいターゲットを削除しているかどうか、チェックする
127       using namespace std;
128       assert( !pt.get() || pt.get() == target );
129       
130       // これが呼ばれた後に shared_ptr の働きでこのオブジェクトが破棄され、
131       // 同時に pt の有効期限も切れるので、ここでは何もしない
132     }
133     
134    private:
135     // メンバとして Pointer を保持する
136     Pointer pt;
137   
138   };  // to_shared_holder<Pointer>
139   
140   // 汎用版の本体は単なるラッパ
141   template<typename P>
142   inline shared_ptr<typename P::element_type> to_shared( const P& pt )
143   {
144     return to_shared_holder<P>::to_shared( pt );
145   }
146   
147 }   // namespace gintenlib
148
149 #endif  // #ifndef GINTENLIB_INCLUDED_TO_SHARED_HPP_