スマートポインタ
テンプレート嫌いのせいもあって全然触ってなかったboostだけど、
ちょこっとだけshared_ptrを使ってみたらすごく便利で偉く感動してしまったので、どうやって実装してるのかなぁと考えながら実装してみました。
どこかまずいかも知れないけどテストコードは動いてるしまぁいいか。
参照カウンタのメモリを動的に作成するのが嫌な感じだけど、そのあたりははプールクラス作って管理すればいいかもね。
VC.NETで確認。
iostreamは嫌いなので使ってません。printf万歳。
shared_ptrの中身を見たら、!とかもオーバーロードしてたのでやっぱりそこまでやんないとだめっすよ
&NULLチェックもしろよ見たいな感じ。
明示的なDeleteも必要かな。細かいこと言い出すとキリがない。
後、tabが8で表示されるのが気持ち悪い。
#include "stdafx.h" #include <windows.h> #include <conio.h> // オリジナル共有ポインタ. template<class T> class my_shared_ptr { private: DWORD *m_pdwRefCount; // 参照カウント共有メモリ. T *m_pRef; // 参照ポインタ. // 公開. public: my_shared_ptr() { Zero(); } my_shared_ptr(T *p) { Zero(); if ( p ) { m_pRef = p; m_pdwRefCount = new DWORD; *m_pdwRefCount = 0; IncRef(); } } // コピーコンストラクタ. my_shared_ptr( const my_shared_ptr<T> &p ) { Zero(); *this = p; } ~my_shared_ptr() { DecRef(); } // 参照演算子オーバーロード. T *operator ->() { return m_pRef; } void operator = ( const my_shared_ptr<T> &ptr ) { // すでに何かしかの参照を得ている場合参照カウンタを減らし. // その後でコピーを実行する. DecRef(); // コピー. m_pdwRefCount = ptr.m_pdwRefCount; m_pRef = ptr.m_pRef; // 参照回数を増やす. IncRef(); } // 参照を変更する. void Reset( T *p ) { DecRef(); // コピー. m_pRef = p; // 参照カウンタの作成. // 仮にDecRefでpdwRefCountが0になっていない場合はほかで参照があるのでたぶん大丈夫. m_pdwRefCount = new DWORD; *m_pdwRefCount = 0; IncRef(); } inline DWORD GetCount(void) { if ( !m_pdwRefCount ) return 0; return (*m_pdwRefCount); } // 非公開関数. private: void IncRef(void) { if ( !m_pdwRefCount ) return; (*m_pdwRefCount)++; } void DecRef(void) { if ( !m_pdwRefCount ) return; (*m_pdwRefCount)--; // 参照が無くなったら開放!. if ( *m_pdwRefCount == 0 ) { // 開放. delete m_pRef; delete m_pdwRefCount; m_pdwRefCount = NULL; m_pRef = NULL; } } void Zero(void) { m_pdwRefCount = NULL; m_pRef = NULL; } }; class A { public: int a; A() { a = 0; printf("construct a = %d\n", a); } A(int val) { a = val; printf("construct a = %d\n", a); } ~A() { printf("destruct a = %d\n", a); a = 0; } }; // class Aを引数に取る関数はどうなるか。 // コピーコンストラクタが呼ばれる. void Test( my_shared_ptr<A> ptr ) { printf("ref = %d\n", ptr.GetCount() ); } // 参照はどうか.. void TestRef( my_shared_ptr<A> &ptr ) { printf("ref = %d\n", ptr.GetCount() ); } int _tmain(int argc, _TCHAR* argv[]) { { my_shared_ptr<A> ptrA1; { my_shared_ptr<A> ptrA( new A ); ptrA1 = ptrA; // 参照が増える. Test( ptrA ); // 値渡しの場合も参照が増える. TestRef( ptrA ); // 参照渡しの場合は増えないし、減らない getch(); // セットしなおす. ptrA.Reset( new A(100) ); getch(); } } getch(); return 0; }