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

About this Archive

This page is an archive of entries from April 2010 listed from newest to oldest.

March 2010 is the previous archive.

May 2010 is the next archive.

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