10

一般的なシングルトンを実装しようとする次のクラスがあります。

struct BaseObject
{
   virtual ~BaseObject() {}
};
class _helper
{
private:
    template<typename T> friend class Singleton;
    set<BaseObject*> _s;
    static _helper& _get()
    {
        static _helper t;
        return t;
    }
    _helper()
    {
        cout<<" _helper ctor"<<endl;
    }
    ~_helper()
    {
        cout<<" _helper dtor"<<endl;
        //assert(_s.empty());
    }
};

// Singleton<foo>::Instance() returns a unique instance of foo
template <typename T>
class Singleton : virtual private T
{
public:
    static T& Instance()
    {
        static Singleton<T> _T;
        return _T;
    } 

private:
    Singleton()
    {
        cout<<"inserting into helper "<<typeid(T).name()<<" ptr "<<this<<endl;
        assert(!_helper::_get()._s.count(this));
        _helper::_get()._s.insert(this);
    }
    ~Singleton()
    {
        cout<<"erasing from helper "<<typeid(T).name()<<" ptr "<<this<<endl;
        assert(_helper::_get()._s.count(this));
        _helper::_get()._s.erase(this);
    }
};

Singleton< bar>::Instance()を呼び出してから を呼び出すとSingleton< foo>::Instance()、次の出力が表示されます。

 inserting into helper 3bar ptr 0x509630  
 _helper ctor  
 inserting into helper 3foo ptr 0x509588  
 erasing from helper 3foo ptr 0x509588  
 erasing from helper 3bar ptr 0x509630  
 _helper dtor  

ただし、場合によっては、次のように表示されます。

 inserting into helper 3bar ptr 0x509630  
 _helper ctor  
 inserting into helper 3foo ptr 0x509588  
 erasing from helper 3bar ptr 0x509630  
 _helper dtor  
 erasing from helper 3foo ptr 0x509588  

bar2 番目のケースでは、それらが構築されたのとfoo同じ順序で破壊されたことに注意してください。これは、fooおよびbarシングルトンが共有ライブラリ (.so) 内で静的参照としてインスタンス化されている場合に発生するようです。

static bar& b = Singleton<bar>::Instance();   
static foo& f = Singleton<foo>::Instance();   

なぜそれがそれをするのでしょうか?

4

2 に答える 2

1

これは、シングルトンとヘルパーが異なる変換単位または異なる共有オブジェクトに配置されている場合に発生する可能性があります。テンプレートインスタンスがどの変換ユニットで終了するかを予測するのはかなり難しいことに注意してください。また、各共有オブジェクトは、sayの独自のインスタンスを取得できることにも注意してSingleton<foo>::_Tください。したがって、ある種の共有オブジェクトごとのシングルトンがあります(あまり有用ではありません)。

最後のオブジェクトがヘルパーから削除される前に、ヘルパーが破棄されることに注意してください。これにより、終了時にプログラムがクラッシュします。はい、まさにこのことが私に起こりました。_helperクラスにオブジェクトカウンターを実装して、少なくとも1つのオブジェクトが登録されるまでオブジェクトカウンターが破棄されないようにする必要があります。または、ヒープにすべてのシングルトンを割り当て、その存続期間が終了したときにヘルパーにそれらを破棄させます。

update 2つの静的オブジェクトが同じダイナミックライブラリによって所有されている場合、この破棄順序の反転はおそらく発生しません。それは間違いなく他の方法で起こる可能性があり、実際に起こります。ここでプログラマーは、ダイナミックライブラリの境界を越えて静的オブジェクトをエクスポートしないようにアドバイスされています。

于 2012-05-02T21:07:12.450 に答える
0

static _helper t;私が知る限り、1つのアドレスを定義します。

static _helper& _get()
{
    static _helper t;
    return t;
}

しかし、2つの異なるオブジェクトに使用しようとしているようです。

とにかく、シングルトンにテンプレートが使用されているのを見たことがありません。そして、あなたの場合、シングルトンを破壊しようとしているように見えます。それも前に見たのを覚えていません。シングルトンは通常、一度作成され、プログラムを終了するまで残ります(そして、プログラムを終了するときに割り当てられます)。

それ以外の場合は、共有ポインターまたは侵入参照カウントオブジェクトを調べたいと思うかもしれません。

于 2012-05-08T08:51:31.523 に答える