1 #ifndef GINTENLIB_INCLUDED_CLONABLE_PTR_HPP_
2 #define GINTENLIB_INCLUDED_CLONABLE_PTR_HPP_
6 <gintenlib/clonable_ptr.hpp>
8 clonable_ptr : 深いコピーが可能な参照カウント式スマートポインタ
14 typedef T element_type;
17 typedef typename boost::add_reference<T>::type reference;
24 explicit clonable_ptr( U* p );
27 clonable_ptr( const clonable_ptr& src );
29 clonable_ptr( const clonable_ptr<U>& src );
35 void swap( clonable_ptr& other );
36 friend void swap( clonable_ptr& one, clonable_ptr& another );
39 clonable_ptr& operator=( const clonable_ptr& rhs );
41 clonable_ptr& operator=( const clonable_ptr<U>& rhs );
51 friend T* get_pointer( const clonable_ptr& );
52 T* operator->() const;
55 operator unspecified_bool_type() const;
56 bool operator!() const;
60 int use_count() const;
61 // 参照するオブジェクトが、このポインタのみから参照されている場合 true
65 clonable_ptr<typename boost::remove_const<T>::type> clone() const;
66 // unique でなければ参照するオブジェクトを複製して unique にする
70 shared_ptr<T> to_shared() const;
71 friend shared_ptr<T> to_shared( const clonable_ptr& target );
77 template<typename T1, typename T2>
78 inline bool operator==( const clonable_ptr<T1>&, const clonable_ptr<T2>& );
79 template<typename T1, typename T2>
80 inline bool operator!=( const clonable_ptr<T1>&, const clonable_ptr<T2>& );
81 template<typename T1, typename T2>
82 inline bool operator<( const clonable_ptr<T1>&, const clonable_ptr<T2>& );
85 template<typename T1, typename T2>
86 friend clonable_ptr<T1> static_pointer_cast( const clonable_ptr<T2>& src );
87 template<typename T1, typename T2>
88 friend clonable_ptr<T1> dynamic_pointer_cast( const clonable_ptr<T2>& src );
89 template<typename T1, typename T2>
90 friend clonable_ptr<T1> const_pointer_cast( const clonable_ptr<T2>& src );
93 対象の「深いコピー」を生成できる参照カウント式スマートポインタ。
94 主に対象の型を正確に記憶し複製する程度の機能を持ちます。
95 特に便利なのが to_unique メンバ関数で、このポインタの存在理由の大半がこれに集約されます。
96 コピーにコストのかかるオブジェクトを扱うとき、普段は浅いコピーでコピーコストを削減、
97 オブジェクトに変更を加えるときはその前に to_unique を呼び出す、なんて使い方が一般的かと。
98 もちろん、「対象のオブジェクトの正確なコピーを作れる」という点に着目した使い方もアリです。
99 高機能ですが、コピー不能なオブジェクトはそもそも格納できないので、そこだけは注意が必要。
100 また、仮想関数とテンプレートを使った実装なので、コンパイル後のサイズは大きくなります。
101 便利だけど頼りすぎず、他の上手い実装があればそちらを優先してやってください。
105 #include "pointer_facade.hpp"
106 #include "reference_counter.hpp"
107 #include "shared_ptr.hpp" // for to_shared
109 #include <boost/intrusive_ptr.hpp>
110 #include <boost/type_traits/remove_const.hpp>
111 #include <utility> // for std::pair
118 struct clonable_counted_base
119 : reference_counter<clonable_counted_base>
121 // virtual destructor
122 virtual ~clonable_counted_base(){}
125 typedef std::pair<clonable_counted_base*, void*> cloned_type;
126 virtual cloned_type clone() const = 0;
128 }; // clonable_counted_base
130 // make_clonable 用 impl
131 template< typename T >
132 struct clonable_counted_impl_obj
133 : clonable_counted_base
136 explicit clonable_counted_impl_obj( const T& src )
140 // virtual ~clonable_counted_impl_obj() {}
143 typedef typename boost::remove_const<T>::type T_;
144 typedef clonable_counted_impl_obj<T_> impl_type;
146 using clonable_counted_base::cloned_type;
147 virtual cloned_type clone() const
149 impl_type* pt = new impl_type(obj);
150 return std::make_pair( pt, pt->get() );
153 // 保持するオブジェクトのアドレスを取得
154 T* get() { return &obj; }
159 }; // clonable_counted_impl_obj
162 template< typename T >
163 struct clonable_counted_impl_p
164 : clonable_counted_base
166 explicit clonable_counted_impl_p( T* p_ )
170 virtual ~clonable_counted_impl_p()
172 boost::checked_delete(p);
176 using clonable_counted_base::cloned_type;
177 typedef typename boost::remove_const<T>::type T_;
178 typedef clonable_counted_impl_obj<T_> impl_type;
179 virtual cloned_type clone() const
181 impl_type* pt = new impl_type(*p);
182 return std::make_pair( pt, pt->get() );
186 T* get() const { return p; }
191 }; // clonable_counted_impl_p
194 // cloning_ptr 用の参照カウンタ
195 struct clonable_count
200 // T 型のオブジェクト p_ に関連付けられたカウンタを作る
202 explicit clonable_count( T* p_ )
203 : p( p_ ? new clonable_counted_impl_p<T>(p_) : 0 ) {}
205 // clonable_counted_base* からの構築
206 clonable_count( clonable_counted_base* p_ )
209 // デストラクタは自動定義された奴でおk
210 // ~clonable_count(){}
213 void swap( clonable_count& other )
217 friend void swap( clonable_count& one, clonable_count& another )
223 typedef std::pair<clonable_count, void*> cloned_type;
224 // clonable_count は clonable_counted_base* から暗黙変換できる
225 cloned_type clone() const
227 return p ? cloned_type( p->clone() ) : cloned_type( 0, 0 );
231 int use_count() const { return p ? p->use_count() : 0; }
233 bool unique() const { return use_count() == 1; }
236 boost::intrusive_ptr<clonable_counted_base> p;
240 class clonable_ptr_tag {};
242 } // namespace detail_
248 : pointer_facade< clonable_ptr<T>, T, detail_::clonable_ptr_tag >
251 typedef clonable_ptr this_type;
252 typedef detail_::clonable_count clonable_count;
256 clonable_ptr() : p(), count() {}
260 explicit clonable_ptr( U* p_ )
261 : p( p_ ), count( p_ ) {}
263 // copy constructor では clone しない
264 clonable_ptr( const clonable_ptr& src )
265 : p( src.p ), count( src.count ) {}
267 clonable_ptr( const clonable_ptr<U>& src )
268 : p( src.p ), count( src.count ) {}
270 // デストラクタの処理は clonable_count に任せる
271 // ~clonable_ptr() {}
274 void swap( this_type& other )
278 swap( count, other.count );
280 friend void swap( this_type& one, this_type& another )
286 this_type& operator=( const this_type& rhs )
288 this_type(rhs).swap( *this );
292 this_type& operator=( const clonable_ptr<U>& rhs )
294 this_type(rhs).swap( *this );
301 this_type().swap( *this );
306 this_type(p_).swap( *this );
309 // get() さえ定義すれば後は pointer_facade により自動
310 T* get() const { return p; }
316 typedef typename boost::remove_const<T>::type T_;
317 typedef clonable_ptr<T_> cloned_type;
318 cloned_type clone() const
320 return cloned_type( count.clone() );
323 int use_count() const { return count.use_count(); }
324 bool unique() const { return count.unique(); }
325 // unique じゃなければ複製して unique に
328 if( p != 0 && !unique() )
335 struct to_shared_helper
337 to_shared_helper( const clonable_count& count_ )
341 // operator() では何も行わない
342 void operator()( T* ) const {}
345 clonable_count count;
349 shared_ptr<T> to_shared() const
351 return p ? shared_ptr<T>( p, to_shared_helper(count) ) : shared_ptr<T>();
353 friend shared_ptr<T> to_shared( const this_type& target )
355 return target.to_shared();
360 clonable_count count;
362 template<typename U> friend class clonable_ptr;
365 clonable_ptr( const clonable_count& count_, T* p_ )
366 : p(p_), count(count_) {}
367 explicit clonable_ptr( const clonable_count::cloned_type& pair )
368 : p( static_cast<T*>( pair.second ) ), count( pair.first ) {}
371 template<typename T1, typename T2>
372 friend clonable_ptr<T1> static_pointer_cast( const clonable_ptr<T2>& src );
373 template<typename T1, typename T2>
374 friend clonable_ptr<T1> dynamic_pointer_cast( const clonable_ptr<T2>& src );
375 template<typename T1, typename T2>
376 friend clonable_ptr<T1> const_pointer_cast( const clonable_ptr<T2>& src );
378 }; // clonable_ptr<T>
381 template<typename T, typename S>
382 inline clonable_ptr<T> static_pointer_cast( const clonable_ptr<S>& src )
384 return clonable_ptr<T>( src.count, static_cast<T*>(src.p) );
386 template<typename T, typename S>
387 inline clonable_ptr<T> dynamic_pointer_cast( const clonable_ptr<S>& src )
389 T* p = dynamic_cast<T*>(src.p);
390 return p ? clonable_ptr<T>( src.count, p ) : clonable_ptr<T>();
392 template<typename T, typename S>
393 inline clonable_ptr<T> const_pointer_cast( const clonable_ptr<S>& src )
395 return clonable_ptr<T>( src.count, const_cast<T*>(src.p) );
398 } // namespace gintenlib
400 #endif // #ifndef GINTENLIB_INCLUDED_CLONABLE_PTR_HPP_