shared_ptrの実装6
ここまでのまとめ
- shared_ptrでは参照カウンタの管理、インスタンスの管理が完全に隠蔽されている。
- 可能なこと
- shared_ptr< void >
- pimplイディオム(不完全型クラスを使った宣言)
- 暗黙のアップキャスト
- deleterによる削除
- 未実装
- weak_ptrへの変換
- 適当なクラス図
- JUDEを使いました
shared_ptrクラス
//インスタンスの参照を返すための特性 template < typename T > struct shared_ptr_traits { typedef T& reference; }; //shared_ptr< void >の特殊化 template<> struct shared_ptr_traits< void > { typedef void reference; }; //参照カウンタを共有するスマートポインタ template < typename T > class shared_ptr { public: //operato*の戻り値の型 typedef typename shared_ptr_traits< T >::reference reference; //任意のshared_ptrにプライベートメンバを公開 template < typename U > friend class shared_ptr; private: T* ptr; //インスタンスを指すポインタ。所有権はない。 shared_count count; //参照カウンタ、インスタンスの管理クラス public: shared_ptr() : ptr( 0 ) , count() {} //以下のような生成のためのコンストラクタ // shared_ptr< T > p( new T ); // shared_ptr< T > p( new U ); //T <- U // shared_ptr< void > p( new T ); // shared_ptr< int > p( new int ); // shared_ptr< void > p( new int ); template < typename U > explicit shared_ptr( U* ptr ) : ptr( ptr ) , count( ptr ) {} //上記のコピーコンストラクタ template < typename U > shared_ptr( shared_ptr< U > const& sp ) : ptr( sp.ptr ) , count( sp.count ) {} //deleterを指定できるコンストラクタ // void HogeDeleter( Hoge* p ){ delete p; } // struct PiyoDeleter{ void operator()( Piyo* p ){ delete p; } }; // // shared_ptr< Hoge > p( new Hoge, HogeDeleter ); // shared_ptr< Piyo > p( new Piyo, PiyoDeleter() ); template < typename U, typename DeleterT > explicit shared_ptr( U* ptr, DeleterT deleter ) : ptr( ptr ) , count( ptr, deleter ) {} public: reference operator*()const { return *ptr; } T* operator->()const { return ptr; } };
shared_countクラス
//参照カウンタ、インスタンスの管理 class shared_count { private: sp_counted_base* pimpl; //共有オブジェクトのインスタンス public: shared_count() : pimpl( 0 ) {} //新規登録。参照数=1 template < typename T > explicit shared_count( T* ptr ) : pimpl( new sp_counted_impl< T >( ptr ) ) {} //新規登録(deleterによる削除)。参照数=1 template < typename T, typename DeleterT > explicit shared_count( T* ptr, DeleterT deleter ) : pimpl( new sp_counted_impl_del< T, DeleterT >( ptr, deleter ) ) {} //参照数のデクリメント。参照数=0の時delete ~shared_count() { if( pimpl )pimpl->release(); } public: //参照数のインクリメント shared_count( shared_count const& sc ) : pimpl( sc.pimpl ) { if( pimpl )pimpl->addref(); } //既存のポインタの参照数をデクリメント、コピー元をインクリメント shared_count& operator=( shared_count const& sc ) { sp_counted_base* temp = sc.pimpl; if( temp != pimpl ) { if( temp )temp->addref(); if( pimpl )pimpl->release(); pimpl = temp; } return *this; } };
sp_counted_baseクラス
//参照カウンタの共有オブジェクト基底クラス。参照数の管理のみ class sp_counted_base { private: long use_count; //参照数 public: sp_counted_base() : use_count( 1 ) {} virtual ~sp_counted_base() {} public: void addref() { use_count ++; } void release() { if( -- use_count == 0 ) { dispose(); delete this; } } public: //インスタンスの破棄。派生クラスで実装 virtual void dispose() = 0; };
sp_counted_implクラス
//参照カウンタの共有オブジェクト実装クラス。インスタンスの管理 template < typename T > class sp_counted_impl : public sp_counted_base { private: T* ptr; //インスタンスの指すポインタ。所有権あり public: sp_counted_impl( T* ptr ) : ptr( ptr ) {} public: void dispose() { delete ptr; } };
sp_counted_impl_delクラス
//参照カウンタの共有オブジェクト実装クラス(deleter付き)。インスタンスの管理 template < typename T, typename DeleterT > class sp_counted_impl_del : public sp_counted_base { private: T* ptr; //インスタンスの指すポインタ。所有権あり DeleterT deleter; public: sp_counted_impl_del( T* ptr, DeleterT deleter ) : ptr( ptr ) , deleter( deleter ) {} public: void dispose() { deleter( ptr ); } };