2009-04-10 1 views
3

私は多くのものがシングルトンであるユーティリティクラスのライブラリを書いています。私は継承を使ってそれらを実装しました:複数のシングルトンインスタンス

template <class T> 
class Singleton { 
    public: 
     T& getInstance() { 
      if(m_instance == 0) { 
       m_instance = new T; 
      } 

      return m_instance; 
     } 
    private: 
     static T* m_instance; 
}; 

class SomeClass : public Singleton<SomeClass> { 
    public: 
     SomeClass() {} 
     virtual ~SomeClass() {} 

     void doSomething() {;} 
}; 

明らかに、これは実際のクラスではなく、簡単な例です。とにかく、私は次のようなコードを使用してそれを見つける:

SomeClass::getInstance().doSomething(); 

SomeClassの複数のインスタンスを作成します。私はこれが私の図書館(.a)ファイルの外でも内部的にも使用されていることが原因であると考えています。たとえば、自分で作成していないUIライブラリを使用していますが、これは別にコンパイルされており、追加することにしています。これらの追加の中には、私の.aライブラリでも使われているシングルトンを利用するものがあります。

別の編集がこれを引き起こしていますか?他に何か?

問題を回避するための唯一の方法は、必要なシングルトンで初期化するmain.cppファイル内にグローバルオブジェクトを作成することです。私は、このオブジェクトに、私は別のシングルトンを作成するたびに、追加のメソッドを追加する必要が嫌い

GlobalObject::getSomeClass().doSomething() 

:そして、すべてのコードは、以下のような呼び出しで、この共通のグローバルオブジェクトにアクセスします。プラス構文は、最初のアクセス方法を使用して明確にし、より身近なようだ:

SomeClass::getInstance().doSomething(); 

あなたが任意の考え、意見、など

感謝を持っているなら、私に知らせてください。

+2

シングルトンを実装する方法とC++のスレッドセーフティについての素晴らしい議論は、このペーパーで見つけることができます。 http://www.aristeia.com/Papers/DDJ%5FJul%5FAug%5F2004%5Frevised .pdf –

答えて

5

あなたの問題は、テンプレートが完全にインラインであるため、複数のコンパイル単位でインスタンス化されることです。したがって、テンプレートを使用するすべてのコンパイル単位では、コンパイル単位ごとに1つのシングルトンが作成されます。あなたが必要とするのは、すべてのコンパイルユニットが同じテンプレートインスタンス化を参照するように、グローバルリンケージを強制することです。今後のC++標準ではextern templateでこれをサポートします。今すぐできることは、プロジェクトで自動インスタンス化を無効にし、明示的に使用するテンプレートを手動でインスタンス化することです。このようにして、コンパイル単位でテンプレートを使用すると、実装への未知の参照が生成され、明示的なインスタンス化を行う(1つの)コンパイル単位からリンカーが満たすことができます。

+1

グローバルリンクを強制するにはどうすればいいですか? – Setheron

1

同時に複数のスレッドがgetInstanceにアクセスしていますか?これにより、複数のインスタンスが作成される可能性があります。考えてみましょう:

  1. スレッド1が「if (m_instance==0)」を実行し、スレッド2が「if (m_instance==0)」を実行し、スレッド1は、新しいT
  2. スレッド2は、新しいを割り当て、割り当て、それ本当
  3. 見つけ、それ本当
  4. 見つけましたT

そしてそれらの一方が他方を上書きし、そして(コンパイラの最適化、等に依存して)返すインスタンスの一方または他方のいずれか

1

シングルトンから作成するすべてのテンプレートクラスは、独自のスタティックm_instanceメンバを持ちます。テンプレートがインスタンス化されると、実際にテンプレートパラメータのセットごとに異なるクラスが生成されるため、それらは異なるクラス間で共有されません。あなたが継承をしている方法で判断すると、これはおそらく、それから派生するすべてのクラスに対してSingletonのインスタンスに終わることを意味します。おそらく、これがあなたの問題の原因ですか?

関連する問題