Singletonパターンのメリットは
- 不要なインスタンスの生成を禁止することができる。
まずは次のクラス図をご覧ください
このクラス図で重要なのは
- getInstance()メソッド(static Singleton& getInstance())
- privateなコンストラクタ(Singleton)
つぎにソースを見てみましょう、用意するのは次のファイルです。
- main.cpp
- Singleton.h
- Singleton.cpp
#ifndef _SINGLETON_H_ #define _SINGLETON_H_ class Singleton { public: // get instance static Singleton& getInstance(); // ① // to string const char*const toString(); // ② // destructor ~Singleton(); // ③ private: // constructor Singleton(); // ④ Singleton(const Singleton& _singleton); // ⑤ // initialize const bool init(); // ⑥ // operator(=) Singleton& operator=(const Singleton& _singleton); // ⑦ }; #endif
①唯一のインスタンスを取得するためのインタフェースです。
②文字列化のインタフェースです。Singletonパターンとは関係有りません。
③デストラクタです。
④⑤インスタンスの生成を禁止するためにコンストラクタをprivateで宣言しています。
⑥初期化メソッドですSingletonパターンとは関係ありません。
⑦operator=をprivateで宣言することによりインスタンスのコピーを禁止しています。Singletonパターンとは関係有りません。
次にSingleton.cppファイルを見てみます。
#include "Singleton.h" Singleton& Singleton::getInstance() { static Singleton singleton; // ① static bool isAlreadyInit = false; // ② if (isAlreadyInit) { // do nothing... } else { isAlreadyInit = singleton.init(); } return singleton; } // to string const char*const Singleton::toString() { static char* str = "singleton"; return str; } // constructor Singleton::Singleton() { // do nothing... } // destructor Singleton::~Singleton() { // do nothing... } // initialize const bool Singleton::init() { // do nothing... return true; }
①唯一のインスタンスをstaticで定義しています。
②初期化処理を最初の1回だけ行うために初期化済みフラグを定義して初期化したらtrueを代入します。
注:この実装はスレッドセーフではありません。
最後にmain.cppです。
#include "Singleton.h" #includevoid main (void) { Singleton& apple = Singleton::getInstance(); // ① printf("%s\n", apple.toString()); // ② printf("hit any key...\n"); // ③ while(getchar() == EOF); // ④ }
①getInstance()メソッドでインスタンスを取得しています。
②取得したインスタンスのtoString()メソッドを呼び出しています。
③"hit any key..."を標準出力に表示しています。
④いずれかのkeyが押されるまでループしています。
以上でSingletonパターンの説明は終わりです。ソースコードはコピペで動かせるハズですので是非試してみてください。
こんにちは、いつも読ませていただいてます。
返信削除二点指摘させていただきます。
一つ目は、Singleton.cppの
bool isAlreadyInit = false;
にstaticをつけるべきだと思います。これをつけないと、getInstanceが呼ばれる度にinitされてしまいます。
二つ目はそもそもinitがいらないということです。どういう事かといいますと、
static Singleton singleton;
と書くと、一回目のgetInit呼び出しにおいてのみSingletonのコンストラクタが呼ばれるので、初期化を明示的に書く必要はありません。
参考までにコードを書いてみました。
http://ideone.com/lYtQK
コメントありがとうございます。(約一週間放置orz
返信削除コードの指摘より初めてコメントがついてうれしいです。
bool isAlreadyInit = false;
は修正しました。ご指摘ありがとうございます。
init()メソッドについてですが、ご指摘通りですね。
init()自体あっても害は無いし、コメントでご指摘を受けていますし、何より自分で一生懸命考えて書いたコードなのでこのままにしておくことにします。
◆以下超言い訳◆
コンストラクタから仮想関数を呼ばないのが望ましいという点からクラスメソッドに出来るだけinit()を用意する(なにも処理がなくても)ようにしているのでつい用意してしまいました。