BREW Array
BREW で配列を扱う方法について考えてみる。
配列クラスの実装は、メモリプールからメモリを確保するのであればものすごく簡単で、単純に実装出来る。
/*! * @brief 配列を表すためののクラス * * 配列を生成する方法を除けば、Javaの配列と同じ記法で書くことが出来る */ template< class T > class Array{ public: /*! * @brief デフォルトコンストラクタ */ Array() : length( 0 ) , _pObj( null ) , _pRef( null ){} /*! * @brief デストラクタ */ ~Array(){ release(); } /*! * @brief コンストラクタ * * @param num 生成する配列の数 */ explicit Array( int num ) : length( 0 ) , _pObj( null ) , _pRef( null ){ set( num ); } /*! * @brief コピーコンストラクタ */ Array( const Array& s ) : length( 0 ) , _pObj( null ) , _pRef( null ){ set( s ); } /*! * @brief 代入演算子 */ Array& operator=( const Array& s ){ set( s ); return (*this); } /*! * @brief 配列の指定されたインデックスのデータを返す * * 配列オーバーのチェックはしていない * * @param index 配列のインデックス * * @return 指定されたインデックスへの参照 */ __inline T& operator[]( int index ) const{ return get()[ index ]; } /*! * @brief Array オブジェクトが持っている、配列へのポインタを返す * * @return Array オブジェクトが持っている、配列へのポインタ */ __inline T* get() const{ return _pObj; } /*! * @brief 配列を@a num で初期化する * * 配列の実体は、メモリプールから確保される * * @param num 配列の要素数 */ void set( int num ){ release(); if( num <= 0 ) return; length = num; // 参照数をカウントするためのカウンタを確保 _pRef = (uint32*)pool_memory::operator new( sizeof( uint32 ) ); *_pRef = 1; // メモリプールから配列の実体を確保 _pObj = (T*)pool_memory::operator new( sizeof( T ) * num ); // コンストラクタ呼び出し for( int i = 0 ; i < length ; i++ ){ new( &_pObj[ i ] ) T(); } } /*! * @brief 参照数を増加させる */ void set( const Array& s ){ if( (void*)this != (void*)&s ){ release(); _pObj = s._pObj; _pRef = s._pRef; length = s.length; if( _pRef != null ){ ++(*_pRef); } } } /*! * @brief 参照数を減少させる */ void release(){ if( _pRef != null && (--(*_pRef)) == 0 ){ // デストラクタを逆方向から呼び出す for( int i = length - 1 ; i >= 0 ; i-- ){ (&_pObj[ i ])->~T(); } pool_memory::operator delete( _pObj ); pool_memory::operator delete( _pRef ); } _pObj = null; _pRef = null; length = 0; } int length; //!< 要素数 private: T* _pObj; //!< 配列の実体 uint32* _pRef; //!< 参照カウント数 };
// 2 次元のジャグ配列生成 Array< Array< Hoge > > hogeArrays( 10 ); for( int i = 0 ; i < 10 ; i++ ){ // i 番目の配列に i 個の Hoge を割り当てる hogeArrays[ i ].set( i ); }
// 配列の全ての要素に対して処理を行う for( int i = 0 ; i < hogeArrays.length ; i++ ){ for( int j = 0 ; j < hogeArrays[ i ].length ; j++ ){ hogeArrays[ i ][ j ].something(); } }
ぶっちゃけると、もうこれで十分使えます。
あとは容量を減らすために型に依存しない処理をテンプレートの外に出すぐらいです。
ただ、自分の場合は2つの理由でこの配列クラスを使いません。
- 外部からポインタをセット出来るようにしたい。どうしても大きな配列になってくるとメモリプールから確保するわけにはいかず、そういったときに配列クラスが使えないのは不便だ。
- Array クラスを、BREW Smart Pointer で作った BrewRefObject クラスへキャスト出来るようにしたい。このクラスも BrewRefObject クラスへキャスト出来るようにすることで、配列オブジェクトとそうでないオブジェクトをポリモーフィズム的に扱うことが出来るようになる。
ということで、これらを満たす配列クラスを考えてみます。