C 設計模式 一 單例模式

2021-08-22 06:00:26 字數 3247 閱讀 3535

c++單例模式也稱為單件模式、單子模式。使用單例模式,保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點,該例項被所有程式模組共享。有很多地方需要這樣的功能模組,如系統的日誌輸出等。

單例模式有許多種實現方法,

a. 懶漢式:使用的時候才建立,多執行緒訪問的時候執行緒不安全(雙檢鎖)

b. 餓漢式:類檔案載入的時候已經建立好了物件,如果物件一直沒有使用,則類物件浪費空間

特點與選擇:

在c++中,甚至可以直接用乙個全域性變數做到這一點,但這樣的**顯得很不優雅。定義乙個單例類,使用類的私有靜態指標變數指向類的唯一例項,並用乙個公有靜態方法獲取該例項。如下面的類定義:

//懶漢式 (建立的時候採取new例項)以時間換取空間,執行緒不安全

class csingleton

//在析構函式中析構物件是一種錯誤的做法,會呼叫,是乙個死遞迴,正確做法是建立乙個巢狀的析構類

/*~csingleton()

cout << "~csingleton()" << endl;

} */

private:  

csingleton(){};  

static csingleton * m_pinstance;

};

c++單例模式類csingleton有以下特徵:

大多時候,這樣的實現都不會出現問題,但是設計class應當像設計type一樣,需要考慮初始化和銷毀。再來看m_pinstance指向的空間什麼時候釋放呢?更嚴重的問題是,這個例項的析構操作什麼時候執行?

如果在類的析構行為中有必須的操作,比如關閉檔案,釋放外部資源,那麼上面所示的**無法實現這個要求。我們需要一種方法,正常地刪除該例項。

為什麼不在析構函式中釋放m_pinstance呢?

可以在程式結束時呼叫getinstance並對返回的指標呼叫delete操作。這樣做可以實現功能,但是不僅很醜陋,而且容易出錯。因為這樣的附加**很容易被忘記,而且也很難保證在delete之後,沒有**再呼叫getinstance函式。

乙個妥善的方法是讓這個類自己知道在合適的時候把自己刪除。或者說把刪除自己的操作掛在系統中的某個合適的點上,使其在恰當的時候自動被執行。

我們知道,程式在結束的時候,系統會自動析構所有的全域性變數。事實上,系統也會析構所有的類的靜態成員變數,就像這些靜態成員也是全域性變數一樣。利用這個特徵,我們可以在單例類中定義乙個這樣的靜態成員變數,而它的唯一工作就是在析構函式中刪除單例類的例項。如下面的**中garbage類:

//懶漢式 (建立的時候採取new例項)以時間換取空間,執行緒不安全

class csingleton

void print() 

private:  

csingleton(){};  

static csingleton * m_pinstance;  

class garbage // 它的唯一工作就是在析構函式中刪除 csingleton的例項  

} };  

static garbage garbage; // 定義乙個靜態成員,在程式結束時,系統會呼叫它的析構函式  

};csingleton* csingleton::m_pinstance= null;

csingleton::garbage csingleton::garbo;//靜態類物件類外宣告

類garbage被定義為csingleton的私有內嵌類,以防該類被在其它地方濫用。

在程式執行結束時,系統會呼叫csingleton的靜態成員garbage的析構函式,該析構函式會刪除單例的唯一例項。

使用這種方法釋放c++單例模式物件有以下特徵:

但這是乙個完美的實現嗎?不!該方法是執行緒不安全的,考慮兩個執行緒同時首次呼叫getinstance方法且同時檢測到p是null值,則兩個執行緒會同時構造乙個例項給p,這是嚴重的錯誤!為了保證執行緒安全,可以用鎖。

//懶漢式 執行緒安全式(雙檢鎖)

/* 所謂雙重檢查加鎖機制,指的是:並不是每次進入getinstance方法都需要同步,而是先不

同步,進入方法過後,先檢查例項是否存在,如果不存在才進入下面的同步塊,這是第一重

檢查。進入同步塊過後,再次檢查例項是否存在,如果不存在,就在同步的情況下建立乙個

例項,這是第二重檢查。這樣一來,就只需要同步一次了,從而減少了多次在同步情況下進

行判斷所浪費的時間。

*/class csingleton

return  m_pinstance;

} static pthread_mutex_t mutex;

private:  

csingleton()

static csingleton * m_pinstance;  

class garbage // 它的唯一工作就是在析構函式中刪除 csingleton的例項  

} };  

static garbage garbage; // 定義乙個靜態成員,在程式結束時,系統會呼叫它的析構函式  

};csingleton* csingleton:: m_pinstance= null;

pthread_mutex_t csingleton::mutex;

csingleton::garbage csingleton::garbage;

再來看看餓漢的實現方式,即無論是否呼叫該類的例項,在程式開始時就會產生乙個該類的例項,並在以後僅返回此例項。

由靜態初始化例項保證其執行緒安全性,why?因為靜態例項初始化在程式開始時進入主函式之前就由主線程以單執行緒方式完成了初始化,不必擔心多執行緒問題。

故在效能需求較高時,應使用這種模式,避免頻繁的鎖爭奪。

//餓漢式(在定義例項的時候就去new物件)以空間換時間

class csingleton

private:  

class garbage // 它的唯一工作就是在析構函式中刪除 csingleton的例項  

} };  

csingleton(){};

static csingleton * m_pinstance;

static garbage garbage; // 定義乙個靜態成員,在程式結束時,系統會呼叫它的析構函式  

};csingleton* csingleton::m_pinstance = new csingleton();

csingleton::garbage csingleton::garbage;

C 設計模式(一) 單例模式

單例模式 保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。主要解決 乙個全域性使用的類頻繁地建立與銷毀。何時使用 想控制例項數目,節省系統資源的時候。如何解決 判斷系統是否已存在單例,如果有則返回,沒有則建立。關鍵 建構函式是私有的。單例大約有兩種實現方法 懶漢與餓漢。懶漢 故名思義,不到萬...

C 設計模式(一) 單例模式

1,單利模式 保證乙個類只有乙個例項,並提供乙個訪問它的全域性訪問點,使得系統中只有唯一的乙個物件例項。應用 常用於管理資源,如日誌,執行緒池 實現要點 在類中,要構造乙個例項,就必須呼叫類的建構函式,並且為了保證全域性只有乙個例項。需防止在外部呼叫類的建構函式而構造例項,需要將建構函式的訪問許可權...

設計模式 C 設計模式 單例模式

設計模式 物件導向設計七大原則 設計模式 設計模式概念和分類 設計模式 c 設計模式 單例模式 設計模式 c 設計模式 工廠方法模式 設計模式 c 設計模式 抽象工廠模式 設計模式 c 設計模式 建造者模式 設計模式 c 設計模式 原型模式 作者自用的泛型單例模組 單例模式 singleton pa...