標籤:

c++ 單例模式的一點疑問,求解答?

在《大話設計模式》和一些博客上都看到過一些單例模式的實現,為什麼他們不自定義拷貝構造函數,下面我給出了一個例子,我覺得是應該自定義拷貝構造函數的。另外,需不需要定義class DeleteSingleton用於刪除共享的單例?

#include&

using namespace std;

class Singleton{

private :

int a;

static Singleton *instance;

protected:

Singleton(int v):a(v){ }

//Singleton(const Singleton ins){//複製構造函數

// a=ins.a;

//}

/*class DeleteSingleton{//用於刪除instance

~DeleteSingleton(){

if(Singleton::instance){

delete Singleton::instance;

}

}

};

static DeleteSingleton DelSgl;*/

public:

static Singleton* GetInstance(){

if(instance==NULL){

instance=new Singleton(4);

}

return instance;

}

};

Singleton* Singleton::instance=NULL;

int main(){

Singleton *p=Singleton::GetInstance();

Singleton *p2=Singleton::GetInstance();

cout&<&<(p==p2)&<&

Singleton ins(*p);//這裡如何沒有自定義私有(或protected)拷貝構造函數是可以正常運行的

Singleton *p3=ins;

cout&<&<(p==p3)&<&

system("pause");

return 0;

}


1、其實應該把複製構造函數聲明為=delete,反正不需要複製。

2、DeleteSingleton也是多餘的,畢竟main函數結束以後才delete,跟不delete是沒有任何區別的,進程都要被幹掉了,你還操這個心幹什麼。通常delete都是為了讓內存泄漏檢查演算法不要誤報,從而在main函數裡面手動釋放。


構造析構全放private,拷貝和賦值delete,單例只需要兩行代碼。

static Singleton getInstance()

{

static Singleton instance;

return instance;

}

採用c++11及以上版本編譯,線程安全,lazy-initialize,自動銷毀,完美。


不要用單例這種anti-pattern就行了。


既然是單例了,自然不允許拷貝和轉移啦。講道理是應該delete掉的。

給你看個sample吧

https://github.com/atframework/atframe_utils/blob/master/include/design_pattern/singleton.h

除了你說的delete問題外還有些訪問許可權控制的問題


說多一點:我認為單例實現成什麼樣子,完全取決於具體需要,根本不用那麼教條。比如:

1:業務邏輯是否真的需要(儘可能)嚴格限制全局僅有一個實例?

有些時候業務邏輯並沒有這種限制,那麼連講構造函數設為protected/private都是不需要的。比如隨機數生成器:我提供一個getInstance靜態方法,讓你在要求不高的時候,直接使用全局的實例,避免反覆創建、持有大量PRNG實例帶來的代價;同時也允許你另外構造、持有自己的PRNG實例,以便你在需要特定的隨機數序列的時候,能夠嚴格控制PRNG初始狀態與後續序列。

2:如果1無所謂,不需要嚴格限制全局唯一實例,那麼是否需要限制複製?

如果這個類在業務邏輯上可以複製,那就讓用戶複製唄。

3:是否需要一個人工釋放單例的方法?是否需要多線程訪問?

如果不需要,完全可以把單例簡化成函數包裝的靜態變數:

MyType get_instance()
{
static MyType instance;
return instance;
}

保證在第一次訪問時創建,在程序退出時析構,簡單粗暴。就是不能提前析構。


單例的目的是確保程序處處使用的是一個對象,順帶使用者不需要關心該對象的創建釋放,只有一個也不該複製。一般來說,單例模式和要做成單例的類可以可以分開。不應該給使用者留刪除介面,單例對象基本只該在程序退出時刪除:靜態對象生命期結束調用其析構函數,或者手動用atexit註冊

單例模式主要注意兩點:

1 線程安全,及針對的優化技巧:double check

if(p == nullptr){

scopeguard g(mutex_);

if(p == nullptr)

p = new T;

}

2 單例對象間的依賴順序以及釋放順序

這個比較複雜,大規模C++程序設計 和 《C++設計新思維》里講解比較詳細,直接上github上搜loki看singleton,要確保析構順序就需要自定義的析構所有單例的函數,將其放入atexit來完成。

當然這種代碼很容易封裝的,所以別害怕,你不用每次都寫,把loki的實現摘出來存好就是了。


推薦閱讀:

在替考的代理模式中到底誰是Proxy?
怎樣才能在寫代碼時沒有一種「如履薄冰」的感覺?
用 C++ 編程時,如果不使用設計模式,多層封裝,採用複雜的數據結構,代碼更直觀,易理解,引入(設計模式)後雖然做到了高度的解耦。但是代碼邏輯複雜了,怎麼平衡好?
有哪些在實際 Android 項目中用到的設計模式?
Android 開發中常用到的設計模式有哪些?

TAG:C | 設計模式 |