私の友人は今日、なぜグローバル静的オブジェクトよりシングルトンの使用を好むのか私に尋ねました。 私が説明し始めた方法は、シングルトンが状態を持つことができるということでしたが、静的グローバルオブジェクトはそうではありませんでした...しかし、私は確信が持てませんでした。
他に比べて利点は何ですか? (C ++)
実際には、C ++では推奨される方法はローカル静的オブジェクトです。
Printer & thePrinter() {
static Printer printer;
return printer;
}
これは技術的にはシングルトンですが、この関数はクラスの静的メソッドでさえあり得ます。そのため、グローバルな静的オブジェクトとは異なり、使用する前に構築することを保証します。これは、任意の順序で作成できるため、あるグローバルオブジェクトが別のグローバルオブジェクトを使用すると矛盾なく失敗する可能性があります。
呼び出しによって新しいインスタンスを作成してシングルトンを作成する一般的な方法より優れている点new
つまり、オブジェクトデストラクタはプログラムの最後に呼び出されます。動的に割り当てられたシングルトンでは起こりません。
他の良い方法は、他の静的メソッドやサブクラスからでさえも、singletonにアクセスする方法がないことです。デバッグ時間を節約します。
C ++では、異なるコンパイル単位における静的オブジェクトのインスタンス化の順序は未定義です。したがって、あるグローバルが、構築されていない別のグローバルを参照して、プログラムを破壊する可能性があります。シングルトンパターンは、静的メンバー関数または自由関数に構造を結び付けることによってこの問題を解決します。
まともな要約がありますここに。
cout
そしてcin
前に構築するように特に指定されているmain()
標準による。他のグローバルオブジェクトはこの扱いを受けません。さらに、スレッドセーフなシングルトン実装が存在し、自分で書くのは難しくありません。二重施工を防ぐために必要なのは二重ロックだけです。個人的に私はシングルトンを避けようとしています、私はパターンが使いすぎだと思います。しかし、あなたがC ++の知識を欠いているからといって、私を軽蔑するわけにはいきません。 - rlbond
私の友人は今日、なぜグローバル静的オブジェクトよりシングルトンの使用を好むのか私に尋ねました。私が説明し始める方法は、シングルトンが状態を持つことができるということでした - 静的なグローバルオブジェクトはそうではありませんでした...しかしそれから私は確かではありませんでした。
静的グローバルオブジェクトは、C#でも状態を持つことができます。
class myclass {
// can have state
// ...
public static myclass m = new myclass(); // globally accessible static instance, which can have state
}
他に比べて利点は何ですか? (C ++)
シングルトンはあなたのコードを不自由にしますが、グローバルな静的インスタンスはそうしません。 シングルトンに関する問題については、SOに無数の質問があります。これがひとつ、そしてもう一つ、または別の。
一言で言えば、シングルトンはあなたに2つのことを与えます:
最初のポイントだけが欲しい場合は、グローバルにアクセス可能なオブジェクトを作成する必要があります。 そしてなぜ私たちは二度目が欲しいですか?私たちはしません知っている将来どのようにコードが使用されるのかを事前に判断します。では、なぜそれを特定して有用な機能を削除するのでしょうか。私たちはいつも違う「必要なインスタンスは1つだけになる」と予測したときそして、「1つのインスタンスだけが必要になる」との間には大きな違いがあります(正しい答えはつくる「複数のインスタンスが作成された場合、アプリケーションはどのような状況下でも正常に実行できません。クラッシュし、ユーザーのハードドライブをフォーマットし、インターネットで機密データを公開します。」アプリは壊れていますがもしそうではありません、そうです、そう、シングルトンはあなたが必要とするものです)
cout
そしてcin
しかし、これらは規格で定義されている特別な場合です。 - rlbond
理由1:
シングルトンは作るのが簡単であるのでそれらは怠惰な造りです。
あなたはグローバルでこれを行うことができますが、それは開発者による余分な作業を要します。そのため、デフォルトでは、グローバルは常に初期化されます(名前空間を使った特別な規則は別として)。
そのため、あなたのオブジェクトが大きくて、そして/または構築するのに高価であるならば、あなたが本当にそれを使わなければならない限り、あなたはそれを構築したくないかもしれません。
理由2:
初期化(および破壊)問題の順序
GlobalRes& getGlobalRes()
{
static GlobalRes instance; // Lazily initialized.
return instance;
}
GlobalResTwo& getGlobalResTwo()
{
static GlobalResTwo instance; // Lazy again.
return instance;
}
// Order of destruction problem.
// The destructor of this object uses another global object so
// the order of destruction is important.
class GlobalResTwo
{
public:
GlobalResTwo()
{
getGlobalRes();
// At this point globalRes is fully initialized.
// Because it is fully initialized before this object it will be destroyed
// after this object is destroyed (Guaranteed)
}
~GlobalResTwo()
{
// It is safe to use globalRes because we know it will not be destroyed
// before this object.
getGlobalRes().doStuff();
}
};
グローバル静的オブジェクトに対するシングルトンのもう1つの利点は、コンストラクターが非公開であるため、 "1つしか存在できない"という非常に明確な、コンパイラーによる指示があることです。
それとは対照的に、グローバルな静的オブジェクトでは、開発者がこのオブジェクトの追加のインスタンスを作成するコードを書くのを止めることは何もありません。
追加の制約の利点は、オブジェクトがどのように使用されるかに関して保証があることです。
シングルトン( "最初の使用時に構築")イディオムを使うと、避けることができます。静的初期化順序の失敗
C ++では、実際の有用性という点で両者の間に大きな違いはありません。グローバルオブジェクトは、もちろんそれ自身の状態を維持することができます(私はそれをお勧めしませんが、おそらく他のグローバル変数で)。グローバルオブジェクトまたはシングルトンを使用する場合(および使用しない理由がたくさんあります)、グローバルオブジェクトに対してシングルトンを使用する最大の理由は、シングルトンを使用すると、複数のクラスを継承することで動的多相を持つことができることです。シングルトン基本クラス。
さて、シングルトンを実際に使用する理由は2つあります。一つは、誰もが言っている静的な順序のことです。
もう1つは、コードを使用しているときに、他の人がこのようなことをしないようにすることです。
CoolThing blah;
gs_coolGlobalStaticThing = blah;
さらに悪いことに、
gs_coolGlobalStaticThing = {};
カプセル化の側面は、あなたのインスタンスをバカや悪意のあるジャークから保護します。
Printer
コンストラクタを非公開にして作成することによって、他の誰かによってインスタンス化されることはありませんthePrinter()
友達機能。 - Catskul