« 茨城空港開港 | Home | dpkg-buildpackageメモ »

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の初期化をデフォルトコンストラクタでしかできない。これではちょっとカッコ悪い。もう少し考えなければ。

No TrackBacks

TrackBack URL: http://www.argv.org/~chome/blog/mt-tb.cgi/211

2 Comments

Effective C++ より。

Class Singleton{
public:
static Singleton& getInstance(void);

private:
Singleton(void);
~Singleton();
};

Singleton& Singleton::getInstance(void){
static Singleton s; // 唯一のinstance
return s;
}

static局所変数は、最初に処理が通過した時に初期化される仕様を応用。

別々のインスタンスを指さないし、必ず初期化されている事が保証されるし、
異なるファイルリンケージから同じものへのアクセスが簡単だし、
いいねSingleton。現場で使っています。

About this Entry

This page contains a single entry by chomy published on April 17, 2010 3:20 PM.

茨城空港開港 was the previous entry in this blog.

dpkg-buildpackageメモ is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.