スマート多次元配列
以前、スマートポインタの配列版を作ったが、1次元しか使えなかった。多次元にしたい場合はネストしまくるしか方法がなかった。まあそれでもよいのだが大抵は非常に長くなって煩雑になってしまう。
それよりも初期化が非常に面倒くさい。
smart_array< smart_array< smart_array< int > > > aaaInt; aaaInt( new smart_array< smart_array< int > >[10], 10 ); for( int i = 0; i < 10; ++i ){ aaaInt[i].Reset( new smart_array< int >[20], 20 ); for( int j = 0; j < 20; ++j ){ aaaInt[i][j].Reset( new int[30], 30 ); } }
メモリ確保するだけでいちいちループをまわす必要がある。まあこれも余程ランダムなアクセスを利用する以外はどうせループで回して使うのが普通だからそのついででもいい気もするが(^^;
等と言い出してはきりがない。というわけで作ろう作ろうと思っていたけどなかなか初期化のインターフェースが思いつかず、結構時間が経ってしまった(^^;
初期化を1発で終わらせ、なおかつどの次元でも同じように扱える。そんなことがそもそもC++で可能なのかなと頑張ってみたら何とかできました。
#ifndef __SMART_ARRAY__ #define __SMART_ARRAY__ //-------------------------------------------------------- //参照カウンタつきスマート多次元配列。 //-------------------------------------------------------- template< class P, unsigned int DIMENSION = 1 > class smart_array { public: //デフォルトコンストラクタ。 //・・・・からっぽである。 smart_array(){} //コピーコンストラクタ。 //アップキャストもOK template< class D > smart_array( const smart_array< D,DIMENSION >& p ){ m_arrayObject = p.m_arrayObject; } smart_array( const smart_array& p ){ m_arrayObject = p.m_arrayObject; } //生ポインタコンストラクタ(違) template< class D > smart_array( unsigned int nSize, ... ){ Reset< D >( &nSize ); } smart_array( unsigned int nSize, ... ){ Reset( &nSize ); } //代入演算子 template< class D > smart_array< P, DIMENSION >& operator =( const smart_array< D, DIMENSION >& p ){ m_arrayObject = p.m_arrayObject; return *this; } smart_array& operator =( const smart_array& p ){ m_arrayObject = p.m_arrayObject; return *this; } //配列のふりをする。 smart_array< P, DIMENSION - 1 >& operator( const unsigned int index ){ return m_arrayObject[index]; } //再利用 template< class D > smart_array< P,DIMENSION >& Reset( unsigned int nSize, ... ){ Reset< D >( &nSize ); return *this; } smart_array< P,DIMENSION >& Reset( unsigned int nSize, ... ){ Reset( &nSize ); return *this; } //明示的開放 void Release(){ m_arrayObject.Release(); } //大きさ unsigned int GetSize( unsigned int nDimension = 0 ){ if( nDimension == 0 ){ return m_arrayObject.GetSize(); }else{ return m_arrayObject.GetPtr()->GetSize( nDimension - 1 ); } } template< class Y, unsigned int DIM > friend class smart_array; protected: //再利用の関数の内部的動作 template< class D > void Reset( unsigned int* pnSize ){ m_arrayObject.Reset( new smart_array< P,DIMENSION - 1 >[*pnSize], *pnSize ); for( unsigned int index = 0; index < *pnSize; ++index ){ m_arrayObject[index].Reset< D >( pnSize + 1 ); } } void Reset( unsigned int* pnSize ){ m_arrayObject.Reset( new smart_array< P,DIMENSION - 1 >[*pnSize], *pnSize ); for( unsigned int index = 0; index < *pnSize; ++index ){ m_arrayObject[index].Reset( pnSize + 1 ); } } private: smart_array< smart_array< P,DIMENSION - 1 > > m_arrayObject; }; //-------------------------------------------------------- //参照カウンタつきスマート配列。1次元用 //-------------------------------------------------------- template< class P > class smart_array< P, 1 > { public: //デフォルトコンストラクタ。 //・・・・からっぽである。 smart_array():m_pnCounter( NULL ),m_aObject( NULL ),m_nSize( 0 ){} //コピーコンストラクタ。 //アップキャストもOK template< class D > smart_array( const smart_array< D, 1 >& p ){ if( p != NULL ){ //ポインタコピー m_aObject = p.m_aObject; m_pnCounter = p.m_pnCounter; //参照カウンタ++ (*m_pnCounter)++; //サイズ m_nSize = p.m_nSize; }else{ m_aObject = NULL; m_pnCounter = NULL; m_nSize = 0; } } smart_array( const smart_array& p ){ if( p != NULL ){ m_aObject = p.m_aObject; m_pnCounter = p.m_pnCounter; (*m_pnCounter)++; m_nSize = p.m_nSize; }else{ m_aObject = NULL; m_pnCounter = NULL; m_nSize = 0; } } //生ポインタコンストラクタ(何) //サイズを渡すといろいろ嬉しいことがあるかも。 smart_array( P* p, unsigned int nSize = 0xFFFFFFFF ){ //オブジェクト保管 m_aObject = p; //制御パラ確保 m_pnCounter = new unsigned int; //参照カウンタセット *m_pnCounter = 1; //サイズ m_nSize = nSize; } //代入演算子 template< class D > smart_array< P >& operator =( const smart_array< D, 1 >& p ){ //中身をやさしく削除 Release(); if( p != NULL ){ //メンバコピー m_pnCounter = p.m_pnCounter; m_aObject = p.m_aObject; m_nSize = p.m_nSize; //参照カウンタUP!! (*m_pnCounter)++; } return *this; } smart_array& operator =( const smart_array& p ){ Release(); if( p != NULL ){ m_pnCounter = p.m_pnCounter; m_aObject = p.m_aObject; m_nSize = p.m_nSize; (*m_pnCounter)++; } return *this; } template< class D > smart_array< P >& operator =( D* p ){ //サイズがわからないので非推奨 //中身をやんわり削除 Release(); //ぬるぽ!! if( p != NULL ){ //制御パラ確保 m_pnCounter = new unsigned int; //代入 m_aObject = p; *m_pnCounter = 1; m_nSize = 0xFFFFFFFF; } return *this; } //再利用 template< class D > smart_array< P >& Reset( D* p, unsigned int nSize ){ Release(); if( p != NULL ){ //制御パラ確保 m_pnCounter = new unsigned int; //代入 m_aObject = p; *m_pnCounter = 1; m_nSize = nSize; } return *this; } //再利用:高次元との互換 template< class D > smart_array< P,1 >& Reset( unsigned int nSize, ... ){ Reset( new D[nSize], nSize ); return *this; } smart_array< P,1 >& Reset( unsigned int nSize, ... ){ Reset( new P[nSize], nSize ); return *this; } //ディストラクタ。 virtual ~smart_array(){ Release(); } //明示的開放 void Release(){ //ぬるぽ中 if( m_aObject == NULL ){ return; } //参照カウンタが0なら制御DATAも削除 if( --(*m_pnCounter) == 0 ){ delete m_pnCounter; delete m_aObject; } //初物のふりをする。 m_pnCounter = NULL; m_aObject = NULL; m_nSize = 0; return; } //配列のふりをする。 #ifndef _DEBUG P& operator( unsigned int i ) const { return m_aObject[i] } #else //デバッグ用。配列を超えると例外を投げてくる。 P& operator( unsigned int i ) const { if( i < m_nSize ){ return m_aObject[i]; }else{ throw "Buffer Overflow"; } } #endif protected: //再利用の関数の内部的動作 template< class D > void Reset( unsigned int* pnSize ){ Reset( new P[*pnSize], *pnSize ); } void Reset( unsigned int* pnSize ){ Reset( new P[*pnSize], *pnSize ); } public: //比較演算子 //NULLチェックにも使えます。 bool operator==( const P* p ) const{ return m_aObject == p; } bool operator==( const smart_array< P >& p ) const{ return m_aObject == p.m_aObject; } bool operator!=( const P* p ) const{ return m_aObject != p; } bool operator!=( const smart_array< P >& p ) const{ return m_aObject != p.m_aObject; } //コンテナ的なこと #ifndef _DEBUG unsigned int GetSize(){ return m_nSize; } #endif #ifdef _DEBUG unsigned int GetSize(){ if( m_nSize == 0xFFFFFFFF ){ throw "undefined size"; }else{ return m_nSize; } } #endif unsigned int GetSize( unsigned int ){ return GetSize(); } P* GetPtr(){ return m_aObject; } P* GetEndPtr(){ return m_aObject + m_nSize; } template< class Y, unsigned int DIM > friend class smart_array; private: unsigned int* m_pnCounter; P* m_aObject; unsigned int m_nSize; }; #endif
えっと、ちょっとテンプレート展開が複雑なのでコンパイラを結構選ぶ可能性は高いです。VC.NET2003でしか試してません。
とりあえず、1次元から全次元(メモリとコンパイラが耐えられれば)扱えます。パフォーマンスは全然考えていません(^^; やっていることは以前作ったsmart_arrayをネストしまくったのをラッピングしているだけです。つまり、
smart_array< smart_array< smart_array< .... smart_array< P > .... > > > m_arrayObject;
というのを持っているだけです。結局は1次元のをネストしまくっているだけなので基本的には1次元のをしっかり作っておけばOKなはずなのでそういう作りになっています。
初期化方法および使い方は単純です。
//多次元(今回は4)の場合 smart_array< int, 4 > aaaaInt( 1,2,3,4 ); aaaaInt[0][0][0][0] = 3; //1次元の場合 smart_array< int, 1 > aInt( 6 ); //1次元の場合は従来どおりも扱える。 smart_array< int > aInt( new Int[6], 6 );
実用性はどの程度あるか不明ですがそれなりに便利なんじゃないかな?かな?欠点としては、テンプレートが複雑過ぎてVCのオート・・なんだったっけ?(ぉぃ あの->とか書いたらメソッドがずらりと並ぶ奴、アレが不完全になってしまうこと。うーん、これってそもそもの開発コンセプトから外れてしまっているのでは?(^^;
まあいいか(いいのか