web-dev-qa-db-ja.com

C ++でシングルトンのサンプルを提供してくれる人はいますか?

私は次の方法でシングルトンC++を記述します。

class A {
    private:
        static A* m_pA;
        A();
        virtual ~A();

    public:
        static A* GetInstance();
        static void FreeInstance();

        void WORK1();
        void WORK2();
        void WORK3();
    }
}

A* A::GetInstance() {
    if (m_pA == NULL)
        m_pA = new A();
    return m_pA;
}

A::~A() {
    FreeInstance()  // Can I write this? are there any potential error?
}

void A::FreeInstance() {
    delete m_pA;
    m_pA = NULL;
}

ありがとう! Evan Teranとsep61.myopenid.comの答えは正しく、本当に良いです!私のやり方は間違っています、そのようなコードを書いている人が私の愚かな間違いを避けられることを望みます。

私のプロジェクトのシングルトンAにはスマートポインターのベクトルがあり、別のスレッドもこのベクトルを編集できるため、アプリケーションを閉じると、CMutexをたくさん追加しても常に不安定になります。マルチスレッドエラー+シングルトンエラーにより、1日無駄になりました。

// ------------------------------------------------ -----------新しいシングルトン。次のサンプルに問題があると思われる場合は編集してください。

class A {
    private:
        static A* m_pA;
        explicit A();
        void A(const A& a);
        void A(A &a);
        const A& operator=(const A& a);
        virtual ~A();

    public:
        static A* GetInstance();
        static void FreeInstance();

        void WORK1();
        void WORK2();
        void WORK3();
    }
}

A* A::GetInstance() {
    if (m_pA == NULL){
        static A self;
        m_pA = &self;
    }
    return m_pA;
}

A::~A() {
}
38
user25749

次のような静的オブジェクトを使用すると、削除する必要がなくなります。

if(m_pA == 0) {
    static A static_instance;
    m_pA = &static_instance;
}
12
Evan Teran

なぜ誰もがシングルトンをポインターとして返したいのですか?
参照として返すと、はるかに論理的です!

シングルトンを手動で解放することはできません。誰がシングルトンへの参照を保持しているのか、どのようにしてわかりますか?あなたが知らない(または保証できない)場合、誰も参照を持たない場合(ポインタを介して)、オブジェクトを解放するビジネスはありません。

関数メソッドで静的を使用します。
これにより、一度だけ作成および破棄されることが保証されます。また、無料で遅延初期化を提供します。

class S
{
    public:
        static S& getInstance()
        {
            static S    instance;
            return instance;
        }
    private:
        S() {}
        S(S const&);              // Don't Implement.
        void operator=(S const&); // Don't implement
 };

また、コンストラクタをプライベートにする必要があることに注意してください。また、デフォルトのコピーコンストラクタと代入演算子をオーバーライドして、シングルトンのコピーを作成できないようにします(そうしないと、シングルトンではなくなります)。

また読む:

正しい理由でシングルトンを使用していることを確認します。

一般的なケースでは技術的にスレッドセーフではありませんが、以下を参照してください。
C++関数の静的変数の有効期間は?

GCCには、これを補うための明示的なパッチがあります。
http://gcc.gnu.org/ml/gcc-patches/2004-09/msg00265.html

197
Martin York

C++のシングルトンは、次のように記述できます。

static A* A::GetInstance() {
    static A sin;
    return &sin;
}
4
sep

コピーコンストラクタと代入演算子をプライベートにすることを忘れないでください。

2
Jasper Bekkers

その行を書く理由はないと思います。デストラクタメソッドは静的ではなく、シングルトンインスタンスはその方法で破壊されません。既に作成した静的メソッドFreeInstance()を使用してオブジェクトをクリーンアップする必要がある場合、デストラクタは必要ないと思います。

それ以外は、私が作成したのとほぼ同じ方法でシングルトンを作成します。

1
Odd

Meyersスタイルのシングルトンに対する熱狂的な期間(以前の回答の一部のようにローカルの静的オブジェクトを使用)の後、複雑なアプリでのライフタイム管理の問題に完全にうんざりしました。

アプリの初期化の初期段階で意図的に「インスタンス」メソッドを参照し、必要なときに作成されることを確認し、予測不可能なためにあらゆる種類のゲームを分解して再生することがあります(または少なくとも非常に複雑で、多少隠されている)物事が破壊される順序。

もちろん、YMMVはシングルトン自体の性質に少し依存しますが、巧妙なシングルトン(および巧妙さを取り巻くスレッド化/ロックの問題)に関するワッフルの多くはIMOで過大評価されています。

1
Will Dean

「モダンC++デザイン」を読むと、シングルトンデザインは静的変数を返すよりもはるかに複雑であることがわかります。

1
jab

これらの質問に答えられる限り、この実装は問題ありません。

  1. オブジェクトがいつ作成されるかを知っていますか(newではなく静的オブジェクトを使用する場合、main()がありますか?)

  2. シングルトンには、作成されるまでに準備ができていない依存関係がありますか?新規ではなく静的オブジェクトを使用する場合、この時点でどのライブラリが初期化されていますか?あなたのオブジェクトは、それらを必要とするかもしれないコンストラクタで何をしますか?

  3. いつ削除されますか?

オブジェクトを作成および削除する場所とタイミングを制御するため、new()を使用する方が安全です。しかし、それからあなたはそれを明示的に削除する必要があり、おそらくシステムの誰もそれをいつ行うかを知らない。理にかなっている場合は、そのためにatexit()を使用できます。

メソッドで静的オブジェクトを使用するということは、いつオブジェクトが作成または削除されるのか実際にはわからないということです。同様に、名前空間でグローバル静的オブジェクトを使用し、getInstance()をまったく回避することもできます-それはあまり追加しません。

スレッドを使用すると、大きな問題に直面します。次の理由により、C++で使用可能なスレッドセーフシングルトンを作成することは事実上不可能です。

  1. getInstanceの永続ロックは非常に重い-すべてのgetInstance()で完全なコンテキストスイッチ
  2. ダブルチェックロックは、コンパイラの最適化とキャッシュ/弱メモリモデルが原因で失敗し、実装が非常に難しく、テストが不可能です。あなたがあなたのアーキテクチャをよく知っていて、移植性を持たせたくない限り、私は実際のシステムでそれをしようとはしないでしょう

これらは簡単にグーグルで検索できますが、次は弱いメモリモデルに関する良いリンクです: http://ridiculousfish.com/blog/archives/2007/02/17/barrier

1つの解決策は、ロックを使用することですが、ユーザーがgetInctance()から取得するポインターをキャッシュし、getInstance()が重くなるのを防ぐ必要があります。

別の解決策は、ユーザーが自分でスレッドセーフを処理できるようにすることです。

さらに別の解決策は、単純なロックのある関数を使用し、new()が呼び出されたらロックおよびチェックせずに別の関数に置き換えることです。これは機能しますが、完全な実装は複雑です。

0
n-alexander
//! @file singleton.h
//!
//! @brief Variadic template to make a singleton out of an ordinary type.
//!
//! This template makes a singleton out of a type without a default
//! constructor.

#ifndef SINGLETON_H
#define SINGLETON_H

#include <stdexcept>

template <typename C, typename ...Args>
class singleton
{
private:
  singleton() = default;
  static C* m_instance;

public:
  singleton(const singleton&) = delete;
  singleton& operator=(const singleton&) = delete;
  singleton(singleton&&) = delete;
  singleton& operator=(singleton&&) = delete;

  ~singleton()
  {
    delete m_instance;
    m_instance = nullptr;
  }

  static C& create(Args...args)
  {
    if (m_instance != nullptr)
      {
    delete m_instance;
    m_instance = nullptr;
      }
    m_instance = new C(args...);
    return *m_instance;
  }

  static C& instance()
  {
    if (m_instance == nullptr)
      throw std::logic_error(
        "singleton<>::create(...) must precede singleton<>::instance()");
    return *m_instance;
  }
};

template <typename C, typename ...Args>
C* singleton<C, Args...>::m_instance = nullptr;

#endif // SINGLETON_H
0
amightywind