最近看了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]