スマートポインタ(参照カウント型)
制作方針
C/C++のtemplateの機能を使って実現します。
以下の項目が若干不便ですが、ものすごく便利です。
宣言及び定義はヘッダに書かないといけない。
typenameなどがめんだくさい。
その代わりに柔軟性に富んだシステムを設計可能です。
今回は参照カウンタと言うものを定義してコピーのような処理の場合は
オブジェクトを使いまわすような方法で対応しています。
サンプルソース
#ifndef _SMART_PTR_ #define _SMART_PTR_ #define SAFE_DELETE(p) if(p){delete p;p=0;} //----------------------------------------------------- // SmartPtr ... manage delete pointer //----------------------------------------------------- template<typename T> class SmartPtr { public: explicit SmartPtr(T* ptr=0); SmartPtr(const SmartPtr<T>& ptr); virtual ~SmartPtr(); const SmartPtr<T>& operator=(T* ptr); const SmartPtr<T>& operator=(const SmartPtr<T>& ptr); const T& operator*(); T* const operator->(); private: T* mpPtr; int* mpCnt; void release(); }; //----------------------------------------------------- // Constructor //----------------------------------------------------- template<typename T> SmartPtr<T>::SmartPtr(T* ptr) { mpPtr = ptr; mpCnt = 0; if( ptr ) mpCnt = new int(1); } template<typename T> SmartPtr<T>::SmartPtr(const SmartPtr<T>& ptr) { mpPtr = ptr.mpPtr; mpCnt = ptr.mpCnt; if( mpCnt ) (*mpCnt)++; } //----------------------------------------------------- // Destructor //----------------------------------------------------- template<typename T> SmartPtr<T>::~SmartPtr() { release(); } template<typename T> void SmartPtr<T>::release() { if( mpCnt ) { (*mpCnt)--; if( (*mpCnt) > 0 ) return; SAFE_DELETE(mpCnt); SAFE_DELETE(mpPtr); } } //----------------------------------------------------- // operator input //----------------------------------------------------- template<typename T> const SmartPtr<T>& SmartPtr<T>::operator=(T* ptr) { release(); mpPtr = ptr; mpCnt = 0; if( ptr ) mpCnt = new int(1); return (*this); } template<typename T> const SmartPtr<T>& SmartPtr<T>::operator=(const SmartPtr<T>& ptr) { release(); mpPtr = ptr.mpPtr; mpCnt = ptr.mpCnt; if( mpCnt ) (*mpCnt)++; return (*this); } //----------------------------------------------------- // operator output //----------------------------------------------------- template<typename T> const T& SmartPtr<T>::operator*() { return *mpPtr; } template<typename T> T* const SmartPtr<T>::operator->() { return mpPtr; } #endif // _SMART_PTR_
mpCntは参照カウンタ
mpPtrは管理する対象のポインタ
SAFE_DELETEについてはメモリを安全に解放するマクロを参照してください。
あと、constはずすとエラーになったりするので注意してくださいね。
小ネタ:publicを先に書くといいらしい。(他人が必要なのは実装ではなく利用方法だとか)
テストコード
#include <iostream> class A { private: char a; public: A(char _a):a(_a){ std::cout << a << " CONSTRUCTOR" << std::endl; } ~A(){ std::cout << a << " DESTRUCTOR" << std::endl; } void put(){ std::cout << "THIS IS " << a << std::endl; } }; SmartPtr<A> getA() { SmartPtr<A> a; a = new A('C'); return a; } int main() { std::cout << "START" << std::endl; SmartPtr<A> a( new A('A') ); SmartPtr<A> b( new A('B') ); a = b; a->put(); a = getA(); b = a; a->put(); std::cout << "END" << std::endl; return 0; }
すべての参照が消えたときに解放されます。
つまり、mpCntが0になったときに解放されます。
実行してみると
START A CONSTRUCTOR B CONSTRUCTOR A DESTRUCTOR THIS IS B C CONSTRUCTOR B DESTRUCTOR THIS IS C END C DESTRUCTOR
きちんと解放されているみたいです。
使い道
Factoryクラス等で生成したオブジェクトの管理に使えます。
削除を意識する必要がないので便利です。
アロケータを考えるとまた色んな実装があるんだけれども
これくらいならシンプルで使いやすいです。