shared_ptrの実装9 -weak_ptrの実装-
前回(shared_ptrの実装8 -weak_ptrに対応させる- - while( c++ );)の続き。
weak_ptrを作ります。
sp_counted_base
リソースを管理するための参照数(shared、weak)を保持するクラス。shared_count、weak_countによって共有される共有オブジェクト。
class sp_counted_base { public: sp_counted_base() : shared( 1 ) , weak( 1 ) {} virtual ~sp_counted_base(){} private: int shared; ///< shared_ptr用参照カウンタ int weak; ///< weak_ptr用参照カウンタ //コピー禁止 private: sp_counted_base( sp_counted_base const& ); sp_counted_base& operator=( sp_counted_base const& ); };
sharedの上げ下げ
- addref
- リソースがdeleteされていなければ、sharedのincrement。
- release
- shared==0になったらdispose()でリソースを破棄し、weak_release()でweakをdecrementする。
- dispose
- 派生クラスsp_counted_impl_p、sp_counted_impl_pdで実装。
class sp_counted_base { //shared public: bool addref() { if( shared == 0 )return false; shared ++; return true; } void release() { if( -- shared == 0 ) { dispose(); weak_release(); } } virtual void dispose() = 0; ..略.. };
weakの上げ下げ
- weak_addref
- weakのincrement
- weak_release
- weakをdecrementして0になったら自身をdeleteする。
class sp_counted_base { ..略.. //weak public: void weak_addref() { weak ++; } void weak_release() { if( -- weak == 0 ) { destroy(); } } void destroy() { delete this; } ..略.. };
sp_counted_impl
参照カウンタの上げ下げと、リソースの所有権を持つsp_counted_base派生クラス。
sp_counted_impl_p
リソースの保持とdeleteを行う。
template < typename T > class sp_counted_impl_p : public sp_counted_base { public: void dispose() { delete ptr; } public: sp_counted_impl_p( T* ptr ) : ptr( ptr ) {} private: T* ptr; };
sp_counted_impl_pd
custom deleterによるリソースのdelete。
template < typename T, typename D > class sp_counted_impl_pd : public sp_counted_base { public: void dispose() { del( ptr ); } public: sp_counted_impl_pd( T* ptr, D del ) : ptr( ptr ) , del( del ) {} private: T* ptr; D del; };
shared_count
weak_countからshared_countを生成するためのコンストラクタを追加。
class shared_count { friend class weak_count; private: sp_counted_base* impl; ..略.. public: explicit shared_count( weak_count const& c ); shared_count( weak_count const& c, no_throw_tag ); }; class weak_count{ ... }; inline shared_count::shared_count( weak_count const& c ) : impl( c.impl ) { if( impl == nullptr || !impl->addref() ) { throw bad_weak_ptr(); } } inline shared_count::shared_count( weak_count const& c, no_throw_tag ) : impl( c.impl ) { if( impl != nullptr && !impl->addref() ) { impl = nullptr; } }
weak_count
weak_ptrが保持する参照カウンタクラス。shared_ptrとsp_counted_base*を共有している。
shared_ptrが持つshared_countから生成される。
- コンストラクタ
- weak_addref
- デストラクタ
- weak_release。
- operator=
- コピー元sp_counted_baseのweak_release
- コピー先sp_counted_baseのweak_addref
class weak_count { friend class shared_count; private: sp_counted_base* impl; public: weak_count() : impl( nullptr ) {} weak_count( shared_count const& c ) : impl( c.impl ) { if( impl != nullptr ) impl->weak_addref(); } weak_count( weak_count const& c ) : impl( c.impl ) { if( impl != nullptr ) impl->weak_addref(); } ~weak_count() { if( impl != nullptr ) impl->weak_release(); } public: bool empty()const { return impl == nullptr; } public: weak_count& operator=( shared_count const& c ) { sp_counted_base* temp = c.impl; if( temp != impl ) { if( temp )temp->weak_addref(); if( impl )impl->weak_release(); impl = temp; } return *this; } weak_count& operator=( weak_count const& c ) { sp_counted_base* temp = c.impl; if( temp != impl ) { if( temp )temp->weak_addref(); if( impl )impl->weak_release(); impl = temp; } return *this; } };
weak_ptr
- lock
- リソースが既にdeleteされていればnullptrを指すshared_ptr、まだ生きていればsp_counted_baseを共有するshared_ptrを返す。
- operator*、operator->
template< typename Type > class weak_ptr { public: typedef typename shared_ptr_traits< Type >::reference_t reference_t; public: weak_ptr() : ptr( nullptr ) , count() {} template< typename Y > weak_ptr( weak_ptr< Y > const& p ) : ptr( p.lock().get() ) , count( p.count ) { } template< typename Y > weak_ptr( shared_ptr< Y > const& p ) : ptr( p.ptr ) , count( p.count ) { } public: template< typename Y > weak_ptr& operator=( weak_ptr< Y > const& p ) { ptr = p.lock().get(); count = p.count; return *this; } template< typename Y > weak_ptr& operator=( shared_ptr< Y > const& p ) { ptr = p.ptr; count = p.count; return *this; } public: shared_ptr< Type > lock()const { return shared_ptr< Type >( *this, no_throw_tag() ); } public: reference_t operator*()const { if( ptr == nullptr )throw nullptr_exception(); return *ptr; } Type* operator->()const { if( ptr == nullptr )throw nullptr_exception(); return ptr; } private: Type* ptr; weak_count count; };
test
#include <iostream> #include "smart_ptr/shared_ptr.h" #include "smart_ptr/weak_ptr.h" #include <boost/smart_ptr.hpp> class Hoge { public: void func(){ std::cout << "hoge" << std::endl; } }; int main() { //メモリリークの検出 _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); { hoge::weak_ptr< Hoge > q; { hoge::shared_ptr< Hoge > p( new Hoge() ); q = p; } if( hoge::shared_ptr< Hoge > temp = q.lock() ) temp->func(); } return 0; }
とりあえず、期待通りに動作してるようです。
足りない機能は今後追加予定。