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 からのベタ移植だったらそんなに問題は無いとは思いますが……。