OSDN Git Service

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