社内ライブラリ

今、社内で使うライブラリを書いているんだけれども、このライブラリ、スマートポインタを使用してはならないという方針になっている。
まあ、社内にスマートポインタを扱える人間が少ないということを考えるとそれもありかなぁとか思って、スマートポインタを使わずにライブラリを組んでいた。


しかし、どうしてもスマートポインタが必要な場面が出てくる。
例えば、ライブラリ側と実装側の両方が同じオブジェクトへのポインタを持っている場合、どちらかが解放された場合、もう片方は解放してはならない。


どうにか出来ないかと小一時間程考えていると、ふと LunaCat を思い出した。
そういえばあれは参照型クラスだった。あれを使えばいいんじゃないのか?
あれはスマートポインタを内部で持っているだけだし、やろうと思えばテンプレートを使わなくても書ける。これはいけるかも。


ということで作ってみました。

class Hoge{
protected:
    // クラスの実体
    class Data{
    public:
        virtual ~Data(){}
        
        virtual void foo(){}
        virtual void bar(){}
        
        friend class Factory;
    };
public:
    Hoge() : _pData( null ) , _pRef( null ){
    }
    Hoge( const Hoge& s ) : _pData( null ) , _pRef( null ){
        Set( s );
    }
    ~Hoge(){
        Release();
    }
    // 代入演算子
    Hoge& operator=( const Hoge& s ){
        Set( s );
        return (*this);
    }
    // null の代入演算子
    Hoge& operator=( long ){
        Release();
        return (*this);
    }
    Data* operator->(){
        return _pData;
    }
    // Hoge オブジェクトの生成
    static Hoge create(){
        Hoge hoge;
        
        Data* pData = null;
        int* pRef = null;
        
        if( (pData = new Data) == null ) goto failed;
        if( (pRef = new int) == null ) goto failed;
        
        hoge._pData = pData;
        (*pRef) = 1;
        hoge._pRef = pRef;
        
        return hoge;
    failed:
        if( pData != null ) delete pData;
        if( pRef != null ) delete pRef;
        
        return hoge;
    }
protected:
    void Set( const Hoge& s ){
        if( (void*)this != (void*)&s ){
            Release();
            _pData = (Hoge*)s._pData;
            _pRef = s._pRef;
            if( _pRef != null ){
                ++(*_pRef);
            }
        }
    }
    void Release(){
        if( _pRef != null && --(*_pRef) == 0 ){
            delete _pData;
            delete _pRef;
        }
        _pData = null;
        _pRef = null;
    }
protected:
    Data*   _pData;     // 実体へのポインタ
    int*    _pRef;      // 参照数へのポインタ
    
    friend class Factory;
    friend bool operator==( const Hoge& lhs , const Hoge& rhs );
    friend bool operator!=( const Hoge& lhs , const Hoge& rhs );
    friend bool operator==( const Hoge& lhs , const void* rhs );
    friend bool operator!=( const Hoge& lhs , const void* rhs );
    friend bool operator==( const void* lhs , const Hoge& rhs );
    friend bool operator!=( const void* lhs , const Hoge& rhs );
};

__inline bool operator==( const Hoge& lhs , const Hoge& rhs ){
    return (lhs._pData == rhs._pData);
}
__inline bool operator==( const Hoge& lhs , const Hoge& rhs ){
    return !(lhs == rhs);
}
__inline bool operator==( const Hoge& lhs , const void* rhs ){
    return (lhs._pData == rhs);
}
__inline bool operator!=( const Hoge& lhs , const void* rhs ){
    return !(lhs == rhs);
}
__inline bool operator==( const void* lhs , const Hoge& rhs ){
    return (lhs == rhs._pData);
}
__inline bool operator!=( const void* lhs , const Hoge& rhs ){
    return !(lhs == rhs);
}

コード量が増えるのが難点ですが、どうしても必要なクラス以外使わないのでこれで十分。
これならきっとスマートポインタを使ってはいけないって言ってた上司も納得してくれるでしょう(*´ω`)