web-dev-qa-db-ja.com

C ++シングルトンとグローバルスタティックオブジェクト

私の友人は今日、なぜグローバルな静的オブジェクトよりもシングルトンの使用を好むのかと私に尋ねました。私がそれを説明し始めた方法は、シングルトンが状態対静的グローバルオブジェクトを持つことができるということでした...しかし、その後、私は確信していませんでした..これがC++であるため..

利点は何ですか? (C++)

53
Tom

実際、C++の好ましい方法はローカルの静的オブジェクトです。

Printer & thePrinter() {
    static Printer printer;
    return printer;
}

これは技術的にはシングルトンですが、この関数はクラスの静的メソッドですらあります。したがって、任意の順序で作成できるグローバル静的オブジェクトとは異なり、使用する前に構築することを保証し、あるグローバルオブジェクトが別のグローバルオブジェクトを使用する場合に一貫性のない失敗を可能にします。

newを呼び出して新しいインスタンスを作成するシングルトンを実行する一般的な方法よりも優れているのは、オブジェクトデストラクターがプログラムの最後に呼び出されることです。動的に割り当てられたシングルトンでは発生しません。

別の良い面は、他の静的メソッドやサブクラスからでも、作成される前にシングルトンにアクセスする方法がないことです。デバッグ時間を節約します。

57
vava

C++では、異なるコンパイル単位での静的オブジェクトのインスタンス化の順序は未定義です。したがって、あるグローバルが構築されていない別のグローバルを参照して、プログラムを爆破する可能性があります。シングルトンパターンは、構築を静的メンバー関数または自由関数に結び付けることにより、この問題を解決します。

まともな要約があります こちら

24
rlbond

今日、私の友人が、なぜグローバルな静的オブジェクトよりもシングルトンの使用を好むのかと私に尋ねました。私がそれを説明し始めた方法は、シングルトンが状態対静的グローバルオブジェクトを持つことができないということでした...しかし、その後、私は確信していませんでした..これがC++であるため..(私はC#から来ていました)

静的なグローバルオブジェクトは、C#でも状態を持つことができます。

class myclass {
 // can have state
 // ...
 public static myclass m = new myclass(); // globally accessible static instance, which can have state
}

利点は何ですか? (C++)

シングルトンはコードを不自由にしますが、グローバルな静的インスタンスはそうではありません。 SOシングルトンの問題についてはすでに数え切れないほどの質問があります。 ここに1つおよび別のまたは別の =。

つまり、シングルトンは次の2つのことを提供します。

  • グローバルにアクセス可能なオブジェクト、および
  • インスタンスを1つだけ作成できるという保証。

最初のポイントだけが必要な場合は、グローバルにアクセス可能なオブジェクトを作成する必要があります。そしてwhy 2番目が欲しいのでしょうか?コードを将来どのように使用するかを事前にknowしないので、なぜそれを特定して有用な機能を削除するのですか?通常、「wrong」の場合、「必要なのは1つのインスタンスだけだ」と予測するときです。そして、「1つのインスタンスだけが必要です」(作成 1つのインスタンスに対する正しい答えです)と「複数のインスタンスがある場合、アプリケーションはどのような状況でも正しく実行できません」とは大きな違いがありますクラッシュし、ユーザーのハードドライブをフォーマットし、インターネット上に機密データを公開します。」(ここでの答えは、アプリが壊れている可能性が高いですが、ifそうでない場合は、はい、シングルトンはあなたが必要なものです)

8
jalf

グローバルな静的オブジェクトに対するシングルトンのもう1つの利点は、コンストラクターがプライベートであるため、「1つしか存在できない」という非常に明確なコンパイラー強制のディレクティブがあることです。

それに比べて、グローバルな静的オブジェクトでは、開発者がこのオブジェクトの追加インスタンスを作成するコードを書くのを止めるものは何もありません。

追加の制約の利点は、オブジェクトの使用方法が保証されることです。

4
Andrew Shepherd

理由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();
        }
};
3
Martin York

Singleton( "construct on first use")イディオムを使用すると、 static初期化順序fiasco を回避できます。

3
aJ.

C++では、実際の有用性の点で2つの間に大きな違いはありません。グローバルオブジェクトは、独自の状態を維持できます(他のグローバル変数を使用することもできますが、お勧めしません)。グローバルまたはシングルトンを使用する場合(およびそうでない多くの理由があります)、グローバルオブジェクトに対してシングルトンを使用する最大の理由は、シングルトンを使用して、複数のクラスをシングルトン基本クラス。

0
coppro