Singletonをテンプレート化する

Singletonクラスの続きです。

今回はSingletonクラスをテンプレート化して簡単に定義できるようにしてみたいと思います。

#include <iostream>
using namespace std;

template<class T>
class Singleton {
private:
    class Auto {
    public:
        T* m_instance;
        Auto() : m_instance(0){}
        ~Auto() {
            cout << "~Auto" << endl;
            if ( m_instance ) {
                delete m_instance;
                m_instance = 0;
            }
        }
    };
    static typename Singleton<T>::Auto m_auto;
public:
    static T* getInstance() {
        if ( !m_auto.m_instance ) m_auto.m_instance = new T;
        return m_auto.m_instance;
    }
};

template<class T>
typename Singleton<T>::Auto Singleton<T>::m_auto;

こんな感じのテンプレートクラスを用意します。

使い方は簡単。Singleton化したいクラスのコンストラクタとデストラクタをprivateにし、friendクラスで上記Singletonを定義するだけです。

class Foo {
    friend class Singleton<Foo>;
private:
    Foo() {
        cout << "Foo" << endl;
    };
    ~Foo() {
        cout << "~Foo" << endl;
    };
};

int main () {
    Foo* foo = Singleton<Foo>::getInstance();
    return 0;
}
$ main
Foo
~Auto
~Foo

また、継承して扱うことも出来ます。

// Singleton<Foo>を継承する
class Foo : public Singleton<Foo> {
    friend class Singleton<Foo>;
private:
    Foo() {
        cout << "Foo" << endl;
    };
    ~Foo() {
        cout << "~Foo" << endl;
    };
};

int main () {
    // 継承しているのでFoo::getInstance()でポインタが取れる
    Foo* foo = Foo::getInstance();
    return 0;
}

またauto_ptrを使って実装した場合は、Fooクラスにauto_ptrのfriendクラス登録が必要になります。

class Foo {
    friend class Singleton<Foo>;
    friend class auto_ptr<Foo>;
private:
    Foo() {
        cout << "Foo" << endl;
    };
    ~Foo() {
        cout << "~Foo" << endl;
    };
};

とまぁこんな感じで。