何回かコメントを書かせてもらった、
Singletonクラスにauto_ptrを使うのは案外難しい - (void*)Pないと
こちらの話題。
「auto_ptrからFooを破棄されるかもしれないじゃない」とのことですが、
これは一応 std::unique_ptr を使うことで回避できます(要 C++0x 対応コンパイラ):
#include <iostream> #include <memory> // 好みの書き方に書き直してるけど基本的には変わらない。 class Foo { typedef Foo self_type; public: static self_type* getInstance() { if( !instance_ ) { instance_.reset( new self_type ); } return instance_.get(); } // ただ、それだけだとなんとなく悲しいので、メンバ関数も作ってみる void bar() { std::cout << "bar\n"; } private: // カスタム削除子。インスタンスの削除はここからのみ行なう。 struct deleter { void operator()( self_type const* const p ) const { delete p; } }; // std::unique_ptr は削除子を指定出来る typedef std::unique_ptr<self_type, deleter> instance_type; static instance_type instance_; Foo() { std::cout << "Foo\n"; } ~Foo() { std::cout << "~Foo\n"; } }; Foo::instance_type Foo::instance_; int main() { Foo* foo = Foo::getInstance(); foo->bar(); // メンバ関数呼び出し // delete foo; // コンパイルエラー! // std::auto_ptr<Foo>(foo); // コンパイルエラー! // std::unique_ptr<Foo>(foo); // コンパイルエラー! // std::unique_ptr<Foo, Foo::deleter>(foo); // コンパイルエラー! return 0; }
肝は、unique_ptr にカスタム削除子を持たせられる、という点ですね。
何のことはない、
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/sp_techniques.html#preventing_delete
で紹介されていたテクの unique_ptr 版です。地味に便利。
しかし、個人的に思うのは、それは真の解決ではない、ということです。
シングルトンまとめ - Togetter にまとめてみましたが、
先のコードで真に問題なのは、 getInstance が生ポインタを返している点だ、ということです。
もしここで、 getInstance がポインタではなく参照を返す仕様だとしたら、
main 関数内部の処理は、こうなります。
int main() { Foo& foo = Foo::getInstance(); foo.bar(); // メンバ呼び出しはこっちが自然。 // delete &foo; // これは明らかにおかしい! }
どうでしょう。ポインタと違って、うっかり delete するのは躊躇われる筈です。
この点を考慮して書き直したコードが、以下のものとなります。
http://ideone.com/uhz1m
C++0x ではなく現行の C++03 の規格に準拠したコードは、以下の通り。
http://ideone.com/RURyQ
いずれもインスタンスの取得に参照を使うことで、
「クラス Foo の唯一のインスタンスへの参照を取得している」という意図を明確にしています。
そもそも、生ポインタというものは、 C++ において非常に厄介なシロモノです。
生ポインタを使う事自体が「間違ってる」デザインとまでは言いませんが、
かつてポインタというものが様々な文脈で使われてきた以上、どうしても意図の明確さに劣ってしまいます。
C++ には、より明確に意図を表明できる「参照」や「スマートポインタ」というものが導入されているのです。
生のポインタを使う特別な理由が無い限りは、そちらを使うほうが自然にコードが書けるはず。
コードを工夫してうっかりミスを予防する、という方法も大事ですが、
しかし「うっかりミスが起こり得る」設計、というのは、設計自体が良くない場合も多いのです。
小手先の技術にとらわれず、どうやれば本質的にミスを防げるか、ということを常に考えていきたいですね。
ちなみにシングルトン自身の実装ですが、個人的に
一番良いデザインは @yamasa が post してくれた
static self_type& getInstance() { static self_type instance; return instance; }
というものだと思います。