OSDN Git Service

8a3d1de09c96f87c69905e2c367d5d2baaded7be
[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     汎用版は大部分のスマートポインタを変換してくれるはずですが、今のところ動作保障はできません。
32     動作保障の出来ない汎用版をわざわざ残している理由は、名前空間の自動照会を行えるようにです。
33     Boost.Swap ( http://www.boost.org/doc/libs/1_41_0/libs/utility/swap.html ) と同じように、
34     gintenlib::to_shared( pt ) と記述された場合、 gintenlib 名前空間だけでなく、
35     pt のクラスが定義されている名前空間からも to_shared 関数を探してくれます。
36
37 */
38
39 #include "shared_ptr.hpp"
40 #include "intrusive_to_shared.hpp"
41
42 #include <cassert>
43 #include <memory>
44
45 // friend 関数を使いやすいように
46 // 本体は別の名前空間を使う
47 namespace gintenlib_to_shared_impl_
48 {
49   using gintenlib::shared_ptr;
50   
51   // いわゆる「スマートポインタ」を保持するホルダ
52   // shared_ptr のコンストラクタの第二引数として渡す削除子として使える
53   template<typename Pointer>
54   struct to_shared_holder
55   {
56     typedef typename Pointer::element_type T;
57     typedef shared_ptr<T> shared_t;
58     
59     // 構築
60     to_shared_holder()
61       : pt() {}
62     to_shared_holder( const Pointer& pt_ )
63       : pt( pt_ ) {}
64     
65     // shared_ptr にする
66     static shared_t to_shared( const Pointer& pt_ )
67     {
68       // まず null pointer に対する最適化
69       T* p = pt_.get();
70       if( !p ){ return shared_t(); }
71       
72       // 本体は転送
73       return to_shared_holder(pt_).to_shared();
74     }
75     // 本体
76     // これを実行すると、このオブジェクトは NULL に再設定される
77     shared_t to_shared()
78     {
79       using namespace std;  // for assert()
80       T* p = pt.get();
81       
82       // いったん仮の to_shared_holder を使って shared_ptr を作る
83       // ここで例外が投げられた場合、何も行われず抜けるので安全
84       shared_t temp( p, to_shared_holder() );
85       
86       // 作られた shared_ptr の中身をいじる
87       // ポイントは、ここから仮の to_shared_holder が正しく設定されるまで、例外が投げられないこと
88       
89       // これは例外を投げない
90       to_shared_holder* holder = boost::get_deleter< to_shared_holder >( temp );
91       // 作ったばかりの holder の型が不一致なわけない
92       assert( holder != 0 );
93       
94       // これも大丈夫
95       Pointer& pt_ = holder->pt;
96       // これが一番の山場。普通は swap は nothrow と信じる
97       swap( pt, pt_ );
98       
99       // これで to_shared_pointer の中身が正しく設定された
100       
101       // 一応確認する
102       assert( pt.get() == 0 && pt_.get() == p );
103       
104       // 何故こんな面倒なことをしているかというと、
105       // 深いコピーを行うタイプのスマートポインタも問題なく保持できるようにしたいため。
106       // Pointer p2 = p1; の処理をした後に、 p1.get() == p2.get() である保証はないのです
107       
108       // 完成した shared_ptr を返す
109       return temp;
110     }
111     
112     // 一番大事なはずの削除関数・・・だが
113     // やってることは特に無し
114     typedef void result_type;
115     void operator()( T* target ) throw ()
116     {
117       // 一応、正しいターゲットを削除しているかどうか、チェックする
118       using namespace std;
119       assert( !pt.get() || pt.get() == target );
120       
121       // これが呼ばれた後に shared_ptr の働きでこのオブジェクトが破棄され、
122       // 同時に pt の有効期限も切れるので、ここでは何もしない
123     }
124     
125    private:
126     // メンバとして Pointer を保持するので
127     // これが存在する限り、
128     Pointer pt;
129   
130   };  // to_shared_holder<Pointer>
131   
132   // 「任意ポインタの変換」本体
133   template<typename P>
134   inline shared_ptr<typename P::element_type> to_shared( const P& pt )
135   {
136     return to_shared_holder<P>::to_shared( pt );
137   }
138   
139 } // namespace gintenlib_to_shared_impl_
140
141
142 // 転送
143 namespace gintenlib_to_shared_impl
144 {
145   // これも薄いラッパ
146   template<typename P>
147   inline gintenlib::shared_ptr<typename P::element_type> to_shared_impl( const P& pt )
148   {
149     using namespace gintenlib_to_shared_impl_;
150     return to_shared( pt );
151   }
152   
153 } // namespace gintenlib_to_shared_impl_
154
155
156 namespace gintenlib
157 {
158   // 本体は単なるラッパ
159   template<typename P>
160   inline shared_ptr<typename P::element_type> to_shared( const P& pt )
161   {
162     return ::gintenlib_to_shared_impl::to_shared_impl( pt );
163   }
164   
165   // std::auto_ptr version
166   // 実際のところ必要ないけど
167   template<typename T>
168   inline shared_ptr<T> to_shared( std::auto_ptr<T> pt )
169   {
170     return shared_ptr<T>( pt.release() );
171   }
172   
173   // trivial version
174   template<typename T>
175   inline shared_ptr<T> to_shared( const shared_ptr<T>& pt )
176   {
177     return pt;
178   }
179
180 }   // namespace gintenlib
181
182 #endif  // #ifndef GINTENLIB_INCLUDED_TO_SHARED_HPP_