C ++でシングルトンのサンプルを提供してくれる人はいますか?
-
06-07-2019 - |
質問
次の方法でシングルトン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() {
}
解決
次のような静的オブジェクトを使用すると、削除する必要がなくなります。
if(m_pA == 0) {
static A static_instance;
m_pA = &static_instance;
}
他のヒント
なぜ誰もがシングルトンをポインタとして返したいのですか?
参照がはるかに論理的に見えるので返してください!
シングルトンを手動で解放することはできません。誰がシングルトンへの参照を保持しているのか、どのようにしてわかりますか?参照を持たない(または保証できない)場合(ポインタを介した場合)、オブジェクトを解放するビジネスはありません。
関数メソッドで静的を使用します。
これにより、1回だけ作成および破棄されることが保証されます。また、無料で遅延初期化を提供します。
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
C ++のシングルトンは次のように記述できます。
static A* A::GetInstance() {
static A sin;
return &sin;
}
コピーコンストラクターと代入演算子をプライベートにすることを忘れないでください。
その行を書く理由はないと思う。デストラクタメソッドは静的ではなく、シングルトンインスタンスはその方法で破壊されません。すでに作成した静的メソッドFreeInstance()を使用してオブジェクトをクリーンアップする必要がある場合、デストラクタは必要ないと思います。
それ以外は、私が作成したのとほぼ同じ方法でシングルトンを作成します。
マイヤーズスタイルのシングルトンに対する熱狂的な期間の後(以前の回答の一部のようにローカルの静的オブジェクトを使用)、複雑なアプリのライフタイム管理の問題に完全にうんざりしました。
アプリの初期化の初期段階で意図的に「インスタンス」メソッドを参照し、必要なときにそれらが作成されることを確認してから、あらゆる種類のゲームを分解してプレイすることに気付く傾向があります物事が破壊される予測不可能な(または少なくとも非常に複雑で多少隠された)順序。
もちろん、YMMVはシングルトン自体の性質に少し依存しますが、巧妙なシングルトン(および巧妙さを取り巻くスレッド化/ロックの問題)に関するワッフルの多くはIMOを過大評価しています。
「モダンC ++デザイン」を読んだ場合シングルトン設計は、静的変数を返すよりもはるかに複雑になる可能性があることがわかります。
これらの質問に答えられる限り、この実装は問題ありません。
-
オブジェクトがいつ作成されるか知っていますか(newではなく静的オブジェクトを使用する場合、main()をお持ちですか?)
-
シングルトンには、作成時までに準備ができていない依存関係がありますか?新規ではなく静的オブジェクトを使用する場合、この時点でどのライブラリが初期化されていますか?オブジェクトがコンストラクタで必要とするものは何ですか?
-
いつ削除されますか?
new()を使用すると、オブジェクトを作成および削除する場所とタイミングを制御できるため、より安全です。しかし、それからあなたはそれを明示的に削除する必要があり、おそらくシステムの誰もそれをいつ行うかを知らない。理にかなっている場合は、そのためにatexit()を使用できます。
メソッドで静的オブジェクトを使用するということは、いつ静的オブジェクトが作成または削除されるかを本当に知らないことを意味します。同様に、名前空間でグローバル静的オブジェクトを使用し、getInstance()をまったく使用しないこともできます-あまり追加されません。
スレッドを使用すると、大きな問題が発生します。次の理由により、C ++で使用可能なスレッドセーフシングルトンを作成することは事実上不可能です。
- getInstanceの永続ロックは非常に重い-すべてのgetInstance()で完全なコンテキストスイッチ
- コンパイラの最適化とキャッシュ/弱メモリモデルが原因で二重チェックロックが失敗し、実装が非常に難しく、テストが不可能です。あなたがあなたのアーキテクチャをよく知っていて、移植性を持たせたくない限り、私は実際のシステムでそれをしようとはしないでしょう
これらは簡単にグーグルで検索できますが、ここに弱いメモリモデルに関するリンクがあります: http://ridiculousfish.com/blog/archives/2007/02/17/barrier 。
1つの解決策は、ロックを使用することですが、getInctance()から取得するポインターをユーザーがキャッシュし、getInstance()が重くなるのを防ぐ必要があります。
別の解決策は、ユーザーが自分でスレッドセーフを処理できるようにすることです。
さらに別の解決策は、単純なロックのある関数を使用し、new()が呼び出されたらロックおよびチェックせずに別の関数に置き換えることです。これは機能しますが、完全な実装は複雑です。
パターンに基づいた優れたC ++ライブラリ、ACEがあります。さまざまな種類のパターンに関する多くのドキュメントがあるので、それらの作業を見てください。 http://www.cs.wustl.edu/~schmidt/ACE.html
//! @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