April 2010 Archives
April 17, 2010
Singletonをまじめに書いてみた
SingletonパターンをC++でまじめに書いてみた。Singletonは生成は簡単なんだけれど、後始末が難しい。GoF本とかには、後始末のことはあまり詳しく書かれていなかったような気がする。あとModern C++ Designにこのことは詳しくかかれている。
今回は最初に思いついたリンクカウントを採用してみた。Singletonを参照しているオブジェクトの数を数えておいて、0になったらdeleteする。
#ifndef _SINGLETON_H
#define _SINGLETON_H
namespace impl{
template <class T>
class Singleton{
public:
static Singleton* initInstance()
{
if(linkcount == 0){
instance = new Singleton();
linkcount = 1;
}else{
linkcount+=1;
}
return instance;
}
void destroy()
{
if(0 == (linkcount-=1)){
delete instance;
}
}
T* object(){
return &obj;
}
private:
Singleton(){
}
public:
virtual ~Singleton(){
}
private:
static Singleton *instance;
static int linkcount;
T obj;
};
template <class T> Singleton<T> *Singleton<T>::instance;
template <class T> int Singleton<T>::linkcount = 0;
}
template <class T>
class Singleton{
public:
Singleton(){
s = impl::Singleton<T>::initInstance();
}
T* operator->(){
return s->object();
}
~Singleton(){
s->destroy();
}
private:
Singleton(const Singleton&){}
private:
impl::Singleton<T> *s;
};
#endif // _SINGLETON_H
で、一つしかインスタンスを作りたくないクラスを定義してあげて、::Singletonのテンプレート引数に入れてあげればよい。例えばこんな感じ。
#include "singleton.h"
using namespace std;
class Hello
{
public:
Hello()
{
i = 0;
}
void run()
{
i += 1;
cout<< "Hello World "<< i<< endl;
}
~Hello()
{
cout<< "destroy"<< endl;
}
int i;
};
int main(void)
{
Singleton<Hello> i1;
Singleton<Hello> i2;
Singleton<Hello> i3;
i1->run();
i2->run();
i3->run();
return 0;
}
このテストコードを実行すると、次のようになる。
Hello World 1 Hello World 2 Hello World 3 destroy
同じテンプレート引数の::Singletonインスタンスを複数生成しているが、それらは同じインスタンス変数にアクセスしており、デストラクタは1度しか呼ばれていない。ちゃんと動いているようだ。ただこのコードでは、Helloの初期化をデフォルトコンストラクタでしかできない。これではちょっとカッコ悪い。もう少し考えなければ。
