タイトルの通りです。グローバルに利用可能なクラスのインスタンスを作成するにはどうすればよいですか (たとえば、印刷用のファンクタがあり、これの単一のグローバル インスタンスが必要です (さらに作成する可能性はありますが))。
7 に答える
通常のパターンを使用してシングルトン オブジェクトを作成するために全力を尽くすことは、質問の 2 番目の部分 - 必要に応じてさらに作成する機能 - に対処していません。シングルトンの「パターン」は非常に制限的であり、別の名前のグローバル変数以上のものではありません。
// myclass.h
class MyClass {
public:
MyClass();
void foo();
// ...
};
extern MyClass g_MyClassInstance;
// myclass.cpp
MyClass g_MyClassInstance;
MyClass::MyClass()
{
// ...
}
さて、他のモジュールでは、いつものようにインクルードmyclass.h
して使用してください。g_MyClassInstance
さらに作成する必要がある場合は、呼び出す準備ができているコンストラクターがあります。
まず、グローバル変数が必要なのは「コードの臭い」です(Martin Fowlerによる)。
ただし、必要な効果を実現するには、シングルトンのバリエーションを使用できます。
静的関数変数を使用します。これは、変数が使用されるまで作成されず(これにより遅延評価が得られます)、すべての変数が作成の逆の順序で破棄されることを意味します(したがって、これによりデストラクタが使用されることが保証されます)。
class MyVar
{
public:
static MyVar& getGlobal1()
{
static MyVar global1;
return global1;
}
static MyVar& getGlobal2()
{
static MyVar global2;
return global2;
}
// .. etc
}
シングルトン パターンのわずかな変更として、ライフタイムが異なる複数のインスタンスを作成する可能性も考慮したい場合は、ctors、dtor、および operator= public を作成します。そうすれば、GetInstance を介して単一のグローバル インスタンスを取得できますが、同じ型のヒープまたはスタックで他の変数を宣言することもできます。
ただし、基本的な考え方はシングルトン パターンです。
シングルトンは使用するのに適したパターンですが、独自の欠点があります。シングルトンを使用する前に、Miško Hevery による次のブログをお読みください。
Singleton パターンが探しているものです。
最も単純で並行性の安全な実装は、Scott Meyer のシングルトンです。
#include <iostream>
class MySingleton {
public:
static MySingleton& Instance() {
static MySingleton singleton;
return singleton;
}
void HelloWorld() { std::cout << "Hello World!\n"; }
};
int main() {
MySingleton::Instance().HelloWorld();
}
John Vlissides (GoF の名声から) による分析については、こちらのトピック IV を参照してください。
私はシングルトンを許可することを好みますが、それを強制しないので、コンストラクターとデストラクタを非表示にしないでください。それは私の支持を与えるだけですでに言われていました。
私のひねりは、真のシングルトンを作成してconstrを非表示にする場合を除き、静的メンバー関数を頻繁に使用しないことです。私の通常のアプローチはこれです:
template< typename T >
T& singleton( void )
{
static char buffer[sizeof(T)];
static T* single = new(buffer)T;
return *single;
}
Foo& instance = singleton<Foo>();
プレースメント new の代わりに T の静的インスタンスを使用しないのはなぜですか? 静的インスタンスは、構築順序を保証しますが、破棄順序は保証しません。ほとんどのオブジェクトは構築の逆の順序で破棄されますが、静的変数とグローバル変数です。静的インスタンス バージョンを使用すると、メインの終了後に最終的に不可解な/断続的なセグメンテーション エラーなどが発生します。
これは、シングルトン デストラクタが呼び出されないことを意味します。ただし、とにかくプロセスがダウンし、リソースが再利用されます。これは慣れるのがちょっと大変ですが、現時点ではこれ以上のクロス プラットフォーム ソリューションはないと信じてください。幸いなことに、C++0x には、この問題を解決する破壊順序を保証するための変更が加えられています。コンパイラが新しい標準をサポートしたら、シングルトン関数をアップグレードして静的インスタンスを使用するだけです。
また、実際の実装では、単純な文字配列の代わりに調整されたメモリを取得するためにブーストを使用しますが、例を複雑にしたくありませんでした