天天看點

再探C++的單件實作

最近看了adrianx的大作《C++實作單件的初探》,真是講得很好,不過裡面有一處疏漏。

現對其Singleton類的設計分析如下:

首先,讓我們來對Singleton類進行如下測試:

#include <iostream>

using namespace std;

// 為了給Singleton類的Instance計數

template <typename T>

class Counter

{

public:

    Counter() { ++count; }

    ~Counter() { --count; }

    Counter(const Counter&) { ++count; }

    static size_t HowMany()

    { return count; }

private:

    static size_t count;

};

class Singleton : private Counter<Singleton>

{

private:

    Singleton()

    {

        cout<<"object is ["<<this<<"] Do< Construction"<<endl;

    }

public:

    using Counter<Singleton>::HowMany; // Added by jfwan

    ~Singleton()

    {

        cout<<"object is ["<<this<<"] Do Destruction>"<<endl;

    }

    static Singleton & GetSingleton()

    {

        static Singleton s;

        return s;

    }

    void Dosomething()

    {

        cout<<"object is ["<<this<<"] Do Something"<<endl;

    }

};

int main(int argc, char* argv[])

{

    Singleton& first = Singleton::GetSingleton();

    Singleton second(first);    // 1

    Singleton third(first);     // 2

    cout << "There are " << Singleton::HowMany()

         << " instances of Singleton." << endl;

    return 0;

}

執行結果:

object is [0049F1C0] Do< Construction

There are 3 instances of Singleton.

object is [0012FEB3] Do Destruction>

object is [0012FEBF] Do Destruction>

object is [0049F1C0] Do Destruction>

可以看出Singleton産生了三個Instance,但Construction卻隻被調用了一次,不難看出另外兩個Instance是被Copy Ctor構造出來的,到此,我們已經找到了這段程式中的這個小小的bug了,但如何來去掉這隻‘臭蟲‘呢?

當我們不定義Copy Ctor時,編譯器在需要的時候會産生一個預設的Copy Ctor。分析上面的代碼,對于Singleton Pattern,1,2兩處的用法應該被禁止,對于1,2這種情況來說是很容易的(但它确實應該被禁止掉)。但一旦在程式中有意或無意的使用了by-value的方式進行函數調用

,就不易被我們所發現。這種情況我們應該盡量使它們在compile-time暴露出來。我們可以通過将Destructor置于private section的方法使1,2不能在此定義。因為Singleton的Destructor屬于private section, Compiler将如是抱怨!于是...

但是對于某些類來說,Destructor并不是必需的,而且,有Destructor會降低performance(雖然那隻是一點點,但既然我們能避免,又何樂而不為呢)。是以通過改變Destructor的Access level并不是十分明智!然而我們應該如何阻止諸如1,2之類的行為發生呢?Let me think...

嗯!我們得避免編譯器合成Default copy constructor行為的産生,然而怎樣才能達到這一目的呢?所幸的是,避免編譯器的這種幕後操作并不難。

且看修改後的Singleton類如下所示:

class Singleton : private Counter<Singleton>

{

    // 同上

private: // preventions

    Singleton(const Singleton&);

    Singleton& operator = (const Singleton&);

};

我将Singleton的Copy ctor和Assignment operator聲明為private, 并且不提供定義(這是為了避免被friend或member functions調用)。這樣我們就可以很明顯的使1,2出通不過Compiler!使得該Singleton類成為Singleton Pattern的比較完美的實作。

完整代碼如下:

class Singleton

{

private:

    Singleton()

    {

        cout<<"object is ["<<this<<"] Do< Construction"<<endl;

    }

public:

    ~Singleton()

    {

        cout<<"object is ["<<this<<"] Do Destruction>"<<endl;

    }

    static Singleton & GetSingleton()

    {

        static Singleton s;

        return s;

    }

    void Dosomething()

    {

        cout<<"object is ["<<this<<"] Do Something"<<endl;

    }

private: // preventions

    Singleton(const Singleton&);

    Singleton& operator = (const Singleton&);

};

至此,我們的Singleton類就設計完成了!其中難免還有遺漏之處,還望各位不吝指教!

[email protected]

繼續閱讀