3


0

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

テンプレートクラスSingleton {public:T

m_instanceを返します。プライベート:静的T * m_instance; ;

クラスSomeClass:publicシングルトン{public:SomeClass(){}仮想〜SomeClass(){}

void doSomething(){;}};

明らかにこれは単純な例であり、実際のクラスではありません。 とにかく、私はそのようなコードを使用してそれを見つけています:

SomeClass :: getInstance()。doSomething();

SomeClassのインスタンスを複数作成します。 これは、ライブラリ(.a)ファイルの外部でも内部でも使用されているという事実によると考えています。 たとえば、私は自分で書かれていないUIライブラリを使用していますが、それは別々にコンパイルされ、追加されています。 これらの追加のいくつかは、私の.aライブラリでも使われているシングルトンを利用しています。

個別のコンパイルはこれを引き起こしていますか? 他に何か?

私が問題を回避するために管理した唯一の方法は私が必要とするどんなシングルトンででも初期化する私のmain.cppファイルの中にグローバルオブジェクトを作成することです。 それからすべてのコードは、次のような呼び出しでこの共通のグローバルオブジェクトにアクセスします。

GlobalObject :: getSomeClass()。doSomething()

私は別のシングルトンを作成するたびにこのオブジェクトに追加のメソッドを追加しなければならないのが嫌いです。 その上、最初のアクセス方法を使うと、構文がより明確でより身近なものになります。

SomeClass :: getInstance()。doSomething();

ご意見、ご意見などがありましたら教えてください。

ありがとう。

3 Answer


5


あなたの問題はあなたのテンプレートが完全にインラインであるのであなたのテンプレートが複数のコンパイル単位で具体化されることになっているということです。 したがって、テンプレートを使用するすべてのコンパイル単位で、(コンパイル単位ごとに)1つのシングルトンを作成することになります。 必要なのは、すべてのコンパイル単位が同じテンプレートのインスタンス化を参照するように、グローバルリンケージを強制することです。 今後のC標準はこれをhttp://en.wikipedia.org/wiki/C 0x#Extern_template [extern template]でサポートします。 今できることは、プロジェクトで自動インスタンス化を無効にして、明示的に使用するテンプレートを手動でインスタンス化することです。 この方法でテンプレートをコンパイル単位で使用すると、実装への未知の参照が生成され、明示的なインスタンス化を行う(1)コンパイル単位からリンカがそれを満たすことができます。


1


複数のスレッドが同時にgetInstanceにアクセスしていますか? 複数のインスタンスが作成される可能性があります。 検討してください:

  1. スレッド1は「 + if(m_instance == 0)+」を実行し、trueであると判断します

  2. スレッド2は「 + if(m_instance == 0)+」を実行し、trueであることがわかります

  3. スレッド1が新しいTを割り当てる

  4. スレッド2が新しいTを割り当てる

それから、それらのうちの1つは他を上書きして、どちらか一方のインスタンスまたは他方を返します(コンパイラの最適化などに依存します)。


1


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