2

マルチスレッド環境ではほとんど作業を行っていません。したがって、以下のクラスの getInstance 関数がスレッドセーフかどうかを知る必要があります。シングルトンクラスは次のとおりです。

//Singleton class
class S {
  // intentionally avoided pointer
  static S singleObject;

   // Private constructor   
   s ();
   s (S &);
   s& operator= (const s&);
public:
  // return reference of static object
  s& getInstance ()
  {
    return singleObject;
  }

  /* Normally with static pointer instance, getInstnace look like as
   s& getInstace ()
   {
      // trying to avoid multiple copies of singleObject
      lock_mutex ()

       if (singleObject == null)
          singleObjecct = new S();

      unlock_mutex ();

      return *singleObject;
    }
  */
};

S S::singleObject;

getInstance 関数 (コメントなし) では、静的オブジェクトの参照が返されます。スレッドセーフなメカニズムが必要ですか?

2 番目の getInstance (コメント付き) では、singleObject が null の場合にオブジェクトを作成します。つまり、ロック機構が必要で、同期する必要がありますよね?

4

4 に答える 4

2

getInstance を static として宣言しない限り、それを呼び出すことはできません。この間違いは、ほぼすべての返信に伝播しています。これ以外に、すべての回答にこれ以上追加することはできません。

于 2012-07-26T11:59:27.200 に答える
2

C++11 では、静的インスタンスを静的関数内に配置できます。

class S
{
    private:
        S();
        S(S const&);
        S& operator=(S const&);

    public:
        static S& getInstance ()
        {
            static S singleObject;
            return singleObject;
        }
};

規格のパラグラフ 6.7.4 によると:

静的ストレージ期間 (3.7.1) またはスレッドストレージ期間 (3.7.2) を持つすべてのブロックスコープ変数のゼロ初期化 (8.5) は、他の初期化が行われる前に実行されます。該当する場合、静的ストレージ期間を持つブロック スコープ エンティティの一定の初期化 (3.6.2) は、そのブロックが最初に入力される前に実行されます。実装は、実装が名前空間スコープ (3.6.2) で静的またはスレッド ストレージ期間を持つ変数を静的に初期化することを許可されているのと同じ条件下で、静的またはスレッド ストレージ期間を持つ他のブロック スコープ変数の早期初期化を実行することが許可されています。それ以外の場合、そのような変数は、コントロールがその宣言を最初に通過するときに初期化されます。そのような変数は、初期化の完了時に初期化されたと見なされます。変数の初期化中に制御が同時に宣言に入った場合、同時実行は初期化の完了を待ちます。変数の初期化中に制御が宣言に再帰的に入る場合、動作は未定義です。

于 2012-07-26T10:44:14.897 に答える
2

getInstance 関数 (コメントなし) では、静的オブジェクトの参照が返されます。スレッドセーフなメカニズムが必要ですか?

関数の有効期間外にアクセスしない限りmain、または他のスレッドが非同期アクセスを行う可能性があるときに変更しない限り、どのスレッドからでも安全にアクセスできます。

開始前または終了後にアクセスするmainと (たとえば、別の静的オブジェクトのコンストラクタまたはデストラクタから)、その時点で初期化されていないか、または既に破棄されている危険性があります。それが、2 番目のバージョンなどの「遅延初期化」の動機です。

2 番目の getInstance (コメント付き) では、singleObject が null の場合にオブジェクトを作成します。つまり、ロック機構が必要で、同期する必要がありますよね?

はい、それにはロック機構が必要です。C++11 (または同様の) スレッド モデルをサポートするコンパイラの場合、このような遅延初期化を行うより簡単な方法は、最初にスレッド セーフな方法で初期化される関数静的変数を使用することです。範囲:

S& getInstance ()
{
    static S singleObject;
    return singleObject;
}

これにより、バージョンのメモリ リークも回避されますが、他の静的オブジェクトの前に破棄される危険性が生じます。したがって、静的オブジェクトのデストラクタからアクセスするのは安全ではありません。

一般に、C++ の静的オブジェクトは、そのような死の罠の地雷原であり (何らかのシングルトン アンチパターンでラップしようとしているかどうかに関係なく)、避けるのが最善です。

于 2012-07-26T11:15:42.053 に答える
0

IIRC これは、これ以上の理由で優れています。getInstance が呼び出されるまで、初期化されません (安全にスレッド化されます)。

-編集- いくつかの理由を今思い出しました。そのメソッドが呼び出されない限り、アクセスできません。これを他のクラス コンストラクターで呼び出すことができ、S が初期化されているかどうかを心配する必要はありません。他のクラスと同様に、最初に構築される可能性があり、その場合、クラッシュまたは未定義の動作が発生します。

//Singleton class
class S {
  // intentionally avoided pointer

   // Private constructor   
   s ();
   s (S &);
   s& operator= (const s&);
public:
  // return reference of static object
  s& getInstance ()
  {
    static S singleObject;
    return singleObject;
  }
};
于 2012-07-26T10:27:19.960 に答える