C++における単例パターン(怠け者、餓漢)
5091 ワード
最近コードを書くのは単例の判断を怠ったため、プログラムがすばやく切り替えて何度も起動する時にバグが発生したので、この機会にいくつかの単例モードの構造方式を整理します.単一のインスタンス・モードは、クラスが1つのインスタンスしかないことを保証し、すべてのプログラム・モジュールで共有されるアクセス・ポイントを提供することを意味します.解決方法1(怠け者式) 1つの実装方法は、クラスのプライベート静的ポインタ変数を使用してクラスの一意のインスタンスを指し、共通の静的メソッドでインスタンスを取得する単一のクラスを定義することである.単一のインスタンス・モードは、クラス自体によって一意のインスタンスを管理し、問題を解決する方法を提供します.唯一のインスタンスはクラスの一般的なオブジェクトですが、このクラスを設計すると、インスタンスを1つだけ作成し、このインスタンスにグローバルアクセスできるようにします.ユニークインスタンスクラスSingletonは、静的メンバー関数でインスタンスの作成操作を非表示にします.
ユーザーが一意のインスタンスにアクセスする方法はGetInstance()メンバー関数のみです.この関数を使用しないと、クラスのコンストラクション関数がプライベートであるため、インスタンスを作成する試みは失敗します.GetInstance()は、怠惰初期化を使用します.つまり、この関数が最初にアクセスされたときに返される値が作成されます.GetInstance()以降の呼び出しはすべて、同じインスタンスのポインタを返します.上記で定義したCSingleton単一クラスには、(1一意のインスタンスを指すプライベート静的ポインタm_pInstanceを有する;2一意のインスタンスを取得できる公有関数があり、必要に応じてインスタンスを作成する;(3コンストラクション関数はプライベートであり、外部からこのクラスのインスタンスを作成することはできない.この実装の問題の1つは、m_pInstance変数の解放問題、すなわちインスタンスの解析問題である.プログラムの終了時にGetInstance()メソッドをアクティブに呼び出し、返すポインタdelete操作を行うことができるが、この方法は煩雑であるだけでなく、呼び出し者が忘れると、多くの問題を引き起こす.
上記の問題の解決策の1つは、クラスに静的グローバル変数を定義することであり、プログラムが終了すると、システムがすべてのグローバル変数を自動的に解析することを知っています.システムは、これらの静的メンバーもグローバル変数であるように、すべてのクラスの静的メンバー変数を解析します.このような静的メンバー変数をCSingleton単一クラスで定義し、その構造関数で単一クラスのインスタンスを削除できます.解決方法2(餓漢式) 単一のクラスに静的オブジェクトを追加する方法に満足していない場合は、ローカル静的変数メソッドを使用して構築することもできます.
Singleton singleton=Singleton::GetInstance();この呼び出し方式コンパイラは、クラスのコピーをサポートするために、クラスにデフォルトのコンストラクション関数を生成します.これでは、単一の例の特性に反しますので、少し変更して、ポインタを返します.
コンパイラにそうさせないで、クラスコピーを宣言するコンストラクタ、リロード=オペレータを表示させることもできます.
class CSingleton
{
private:
CSingleton() //
{
}
static CSingleton *m_pInstance;
public:
static CSingleton * GetInstance()
{
if(m_pInstance == NULL) //
m_pInstance = new CSingleton();
return m_pInstance;
}
};
ユーザーが一意のインスタンスにアクセスする方法はGetInstance()メンバー関数のみです.この関数を使用しないと、クラスのコンストラクション関数がプライベートであるため、インスタンスを作成する試みは失敗します.GetInstance()は、怠惰初期化を使用します.つまり、この関数が最初にアクセスされたときに返される値が作成されます.GetInstance()以降の呼び出しはすべて、同じインスタンスのポインタを返します.上記で定義したCSingleton単一クラスには、(1一意のインスタンスを指すプライベート静的ポインタm_pInstanceを有する;2一意のインスタンスを取得できる公有関数があり、必要に応じてインスタンスを作成する;(3コンストラクション関数はプライベートであり、外部からこのクラスのインスタンスを作成することはできない.この実装の問題の1つは、m_pInstance変数の解放問題、すなわちインスタンスの解析問題である.プログラムの終了時にGetInstance()メソッドをアクティブに呼び出し、返すポインタdelete操作を行うことができるが、この方法は煩雑であるだけでなく、呼び出し者が忘れると、多くの問題を引き起こす.
上記の問題の解決策の1つは、クラスに静的グローバル変数を定義することであり、プログラムが終了すると、システムがすべてのグローバル変数を自動的に解析することを知っています.システムは、これらの静的メンバーもグローバル変数であるように、すべてのクラスの静的メンバー変数を解析します.このような静的メンバー変数をCSingleton単一クラスで定義し、その構造関数で単一クラスのインスタンスを削除できます.
class CSingleton
{
private:
CSingleton()
{
}
static CSingleton *m_pInstance;
class CGarbo // CSingleton
{
public:
~CGarbo()
{
if(CSingleton::m_pInstance)
delete CSingleton::m_pInstance;
}
};
static CGarbo Garbo; // , ,
public:
static CSingleton * GetInstance()
{
if(m_pInstance == NULL) //
m_pInstance = new CSingleton();
return m_pInstance;
}
};
class CSingleton
{
private:
CSingleton() //
{
}
public:
static CSingleton & GetInstance()
{
static CSingleton instance; //
return instance;
}
};
Singleton singleton=Singleton::GetInstance();この呼び出し方式コンパイラは、クラスのコピーをサポートするために、クラスにデフォルトのコンストラクション関数を生成します.これでは、単一の例の特性に反しますので、少し変更して、ポインタを返します.
class CSingleton
{
private:
CSingleton() //
{
}
public:
static CSingleton * GetInstance()
{
static CSingleton instance; //
return &instance;
}
};
コンパイラにそうさせないで、クラスコピーを宣言するコンストラクタ、リロード=オペレータを表示させることもできます.
class CSingleton
{
private:
CSingleton() //
{
}
CSingleton(const CSingleton &);
CSingleton & operator = (const CSingleton &);
public:
static CSingleton & GetInstance()
{
static CSingleton instance; //
return instance;
}
};