BREW Array(4)
# kanoke 『(;´Д`)ガーン
.length で配列長を取得できるのを期待していたのに、.length()になってしまってる(私が過去に実装したのと同じ)。残念(´・ω・`)』
メモリのことを考えないのであれば、BrewRefObject に length を付ければ一応実装出来ると思います。
// 参照カウントを行うためのクラス class BrewRefObject{ public: // コンストラクタ BrewRefObject() : _obj( null ) , _ref( null ) , length( 0 ){ } // デストラクタ ~BrewRefObject(){ Release(); } // コピーコンストラクタ BrewRefObject( const BrewRefObject& s ) : _obj( null ) , _ref( null ) , length( 0 ){ Set( s ); } // null に対するコンストラクタ BrewRefObject( long ) : _obj( null ) , _ref( null ) , length( 0 ){ } // 代入演算子 BrewRefObject& operator=( const BrewRefObject& s ){ Set( s ); return (*this); } // null に対する代入演算子 BrewRefObject& operator=( long ){ Release(); return (*this); } // getter void* get() const{ return _obj; } // public にするのはあまり良くないんだけど……。 BrewRefCountDeleterBase* getRefCountDeleter() const{ return _ref; } int length; // 要素数 protected: // オブジェクトをセットします void Set( const BrewRefObject& s ){ if( (void*)this != (void*)&s ){ Release(); _obj = s.get(); _ref = s.getRefCountDeleter(); length = s.length; if( _ref != null ){ _ref->inc(); } } } // 自身の参照数を減らします void Release(){ if( _ref != null && _ref->dec() == 0 ){ _ref->Delete( _obj ); delete _ref; } _obj = null; _ref = null; length = 0; } protected: void* _obj; //!< 実体へのポインタ BrewRefCountDeleterBase* _ref; //!< 参照カウンタ };
// メモリプールから確保されたメモリを解放するためのクラス template< class T > class BrewPoolDeleter : public BrewRefCountDeleterBase{ public: BrewPoolDeleter( int length ) : _length( length ){} virtual void Delete( void* p ){ // p のデストラクタを呼び出す for( int i = _length - 1 ; i >= 0 ; i-- ){ (&(((T*)p)[ i ]))->~T(); } // p を解放 pool_memory::operator delete( p ); } private: int _length; };
// 配列クラス template< class T > class BrewArray : public BrewRefObject{ public: // デフォルトコンストラクタ BrewArray(){} // コピーコンストラクタ BrewArray( const BrewRefObject& s ) : BrewRefObject( s ){} // null に対するコンストラクタ BrewArray( long ) : BrewRefObject( null ){} // 代入演算子 BrewArray& operator=( const BrewRefObject& s ){ return *(BrewArray*)&BrewRefObject::operator=( s ); } // null に対する代入演算子 BrewArray& operator=( long ){ return *(BrewArray*)&BrewRefObject::operator=( null ); } // num 個のオブジェクトをメモリプールから確保 void Set( int num ){ // InnerRelease ではダメ Release(); if( num <= 0 ) return; // メモリプールから必要なメモリを確保 T* ptr = (T*)pool_memory::operator new( sizeof( T ) * num ); // コンストラクタ呼び出し for( int i = 0 ; i < num ; i++ ){ new( &ptr[ i ] ) T(); } // BrewPoolDeleter はメモリプールから確保される _obj = ptr; _ref = new BrewPoolDeleter< T >( num ); length = num; } // ポインタをセット。Deleter は BrewRefCountArrayDeleter template< class U > void Set( U* p , int num ){ Set( p , BrewRefCountArrayDeleter< U >() , int num ); } // Deleter 付きでポインタをセット template< class U , class Deleter > void Set( U* p , Deleter , int num ){ Release(); if( p != null && num > 0 ){ _obj = static_cast< T* >( p ); _ref = new Deleter(); length = num; } } // 演算子オーバーロード __inline T& operator[]( int index ) const{ return get()[ index ]; } __inline T* operator->() const{ return get(); } __inline T& operator*() const{ return *get(); } // オブジェクトへのポインタを取得 __inline T* get() const{ return (T*)_obj; } };
これなら、上位クラスにキャストしても length が保持されます。BrewRefObject を変えているので BrewSmartPtr にも影響を与えますが、こいつは length を 1 として扱うか、もしくは BrewSmartPtr と BrewArray を統合するのもいいかもしれません。
ただ、参照オブジェクトの数 ≧ 実オブジェクトの数なので、参照オブジェクトに対して length を持たせると、使用するメモリの量は増えます。
まあ、Java からのベタ移植だったらそんなに問題は無いとは思いますが……。