C 單例模式

2021-10-01 10:55:25 字數 4320 閱讀 8653

簡述

單例模式(singleton pattern)是設計模式中最簡單的形式之一,其目的是使得類的乙個物件成為系統中的唯一例項。

這種模式涉及到乙個單一的類,該類負責建立自己的物件,同時確保只有單個物件被建立。這個類提供了一種訪問其唯一物件的方式,可以直接訪問,不需要例項化該類的物件。

uml 結構圖

要點單例模式的要點有三個:

單例類有且僅有乙個例項

單例類必須自行建立自己的唯一例項

單例類必須給所有其他物件提供這一例項

從具體實現角度來說,可分為以下三點:

提供乙個 private 建構函式(防止外部呼叫而構造類的例項)

提供乙個該類的 static private 物件

提供乙個 static public 函式,用於建立或獲取其本身的靜態私有物件(例如:getinstance())

除此之外,還有一些關鍵點(需要多加注意,很容易忽視):

執行緒安全(雙檢鎖 - dcl,即:double-checked locking)

資源釋放

區域性靜態變數

這種方式很常見,實現非常簡單,而且無需擔心單例的銷毀問題。

// singleton.h

#ifndef singleton_h

#define singleton_h

// 非真正意義上的單例

class singleton

private:

singleton() {}

};#endif // singleton_h

但是,這並非真正意義上的單例。當使用如下方式訪問單例時:

singleton single = singleton::getinstance();

1這會出現了乙個類拷貝問題,從而違背了單例的特性。產生這個問題原因在於:編譯器會生成乙個預設的拷貝建構函式,來支援類的拷貝。

為了避免這個問題,有兩種解決方式:

將 getinstance() 函式的返回型別修改為指標,而非引用。

顯式地宣告類的拷貝建構函式,並過載賦值運算子。

對於第一種方式,只需要修改 getinstance() 的返回型別即可:

// singleton.h

#ifndef singleton_h

#define singleton_h

// 單例

class singleton

private:

singleton() {}

};#endif // singleton_h

既然編譯器會生成乙個預設的拷貝建構函式,那麼,為什麼不讓編譯器不這麼幹呢?這就產生了第二種方式:

// singleton.h

#ifndef singleton_h

#define singleton_h

#include

using namespace std;

// 單例

class singleton

void dosomething()

private:

singleton() {}  // 建構函式(被保護)

singleton(singleton const &);  // 無需實現

singleton& operator = (const singleton &);  // 無需實現

};#endif // singleton_h

這樣以來,既可以保證只存在乙個例項,又不用考慮記憶體**的問題。

singleton::getinstance().dosomething();  // ok

singleton single = singleton::getinstance();  // error 不能編譯通過

懶漢式/餓漢式

在講解之前,先看看 singleton 的標頭檔案(懶漢式/餓漢式公用):

// singleton.h

#ifndef singleton_h

#define singleton_h

// 單例 - 懶漢式/餓漢式公用

class singleton

// 建構函式(被保護)

private:

static singleton *m_psingleton;  // 指向單例物件的指標

};#endif // singleton_h

懶漢式的特點:

lazy 初始化

非多執行緒安全

優點:第一次呼叫才初始化,避免記憶體浪費。

缺點:必須加鎖(在「執行緒安全」部分分享如何加鎖)才能保證單例,但加鎖會影響效率。

// singleton.cpp

#include "singleton.h"

// 單例 - 懶漢式

singleton *singleton::m_psingleton = null;

singleton *singleton::getinstance()

餓漢式的特點:

非 lazy 初始化

多執行緒安全

優點:沒有加鎖,執行效率會提高。

缺點:類載入時就初始化,浪費記憶體。

// singleton.cpp

#include "singleton.h"

// 單例 - 餓漢式

singleton *singleton::m_psingleton = new singleton();

singleton *singleton::getinstance()

執行緒安全

在懶漢式下,如果使用多執行緒,會出現執行緒安全隱患。為了解決這個問題,可以引入雙檢鎖 - dcl 機制。

// singleton.h

#ifndef singleton_h

#define singleton_h

#include

#include

using namespace std;

// 單例 - 懶漢式/餓漢式公用

class singleton

// 建構函式(被保護)

private:

static singleton *m_psingleton;  // 指向單例物件的指標

static mutex m_mutex;  // 鎖

};#endif // singleton_h

// singleton.cpp

#include "singleton.h"

// 單例 - 懶漢式(雙檢鎖 dcl 機制)

singleton *singleton::m_psingleton = null;

mutex singleton::m_mutex;

singleton *singleton::getinstance()

}return m_psingleton;

}這樣,就可以保證執行緒安全了,但是,會帶來較小的效能影響。

資源釋放

有記憶體申請,就要有對應的釋放,可以採用下述兩種方式:

主動釋放(手動呼叫介面來釋放資源)

自動釋放(由程式自己釋放)

要手動釋放資源,新增乙個 static 介面,編寫需要釋放資源的**:

// 單例 - 主動釋放

static void destoryinstance()

}後在需要釋放的時候,手動呼叫該介面:

singleton::getinstance()->destoryinstance();

方式雖然簡單,但很多時候,容易忘記呼叫 destoryinstance()。這時,可以採用更方便的方式:

// singleton.h

#ifndef singleton_h

#define singleton_h

#include

using namespace std;

// 單例 - 自動釋放

class singleton

// 建構函式(被保護)

private:

static singleton *m_psingleton;  // 指向單例物件的指標

// gc 機制

class gc

}static gc gc;  // 用於釋放單例

};};

#endif // singleton_h

只需要宣告 singleton::gc 即可:

// main.cpp

#include "singleton.h"

singleton::gc singleton::gc::gc; // 重要

int main()

在程式執行結束時,系統會呼叫 singleton 的靜態成員 gc 的析構函式,該析構函式會進行資源的釋放。這種方式的最大優點就是在「不知不覺」中進行,所以,對我們來說,尤為省心。

C 單例模式

include using namespace std 單例類的c 實現 class singleton 構造方法實現 singleton singleton void singleton setvar int var main int main int argc,char argv return ...

C 單例模式

實現方式一 include template typename t class singleton boost noncopyable static void init private static pthread once t ponce statict value template typena...

C 單例模式

效率有點低,但是還算安全的單例模式,靜態成員實現方式 class singleton public static singleton getinstance singleton singleton getinstance unlock return m instance 內部靜態例項的懶漢模式,c ...