C++ 單例模式兩種實(shí)現(xiàn)方式
更新時(shí)間:2026年01月13日 09:53:40 作者:linzihahaha
文章介紹了單例模式的兩種實(shí)現(xiàn)方式:餓漢模式和飽漢模式(懶漢模式),并對比了它們的特性、線程安全、資源占用、啟動(dòng)速度、實(shí)現(xiàn)復(fù)雜度和性能開銷,文章還提供了代碼示例和適用場景建議,感興趣的朋友跟隨小編一起看看吧
一、餓漢模式 (Eager Initialization)
特點(diǎn):類加載時(shí)就立即創(chuàng)建實(shí)例
實(shí)現(xiàn)代碼:
class Singleton {
private:
static Singleton* instance; // 靜態(tài)成員
Singleton() {} // 私有構(gòu)造函數(shù)
~Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton* getInstance() {
return instance; // 直接返回已創(chuàng)建的實(shí)例
}
};
// 關(guān)鍵:類外初始化時(shí)直接創(chuàng)建實(shí)例
Singleton* Singleton::instance = new Singleton();優(yōu)點(diǎn):
- 線程安全:實(shí)例在程序啟動(dòng)時(shí)就創(chuàng)建,多線程訪問時(shí)不會(huì)有競爭問題
- 簡單直觀:實(shí)現(xiàn)簡單,不需要考慮線程同步
- 調(diào)用效率高:
getInstance()直接返回指針,沒有鎖開銷
缺點(diǎn):
- 資源占用早:即使不使用也會(huì)占用內(nèi)存
- 啟動(dòng)慢:如果構(gòu)造復(fù)雜,會(huì)影響程序啟動(dòng)速度
- 依賴順序問題:多個(gè)餓漢單例的初始化順序不確定
二、飽漢模式 (Lazy Initialization)
特點(diǎn):第一次使用時(shí)才創(chuàng)建實(shí)例
基礎(chǔ)版本(非線程安全):
class Singleton {
private:
static Singleton* instance;
Singleton() {}
~Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton* getInstance() {
if (instance == nullptr) { // 第一次檢查
instance = new Singleton(); // 創(chuàng)建實(shí)例
}
return instance;
}
};
Singleton* Singleton::instance = nullptr; // 初始化為空線程安全版本(雙檢鎖):
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;
Singleton() {}
~Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton* getInstance() {
if (instance == nullptr) { // 第一次檢查(避免每次加鎖)
std::lock_guard<std::mutex> lock(mtx); // 加鎖
if (instance == nullptr) { // 第二次檢查(確保只創(chuàng)建一次)
instance = new Singleton();
}
}
return instance;
}
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;C++11 之后更簡潔的線程安全版本:
class Singleton {
private:
Singleton() {}
~Singleton() {}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton& getInstance() {
static Singleton instance; // C++11 保證靜態(tài)局部變量初始化是線程安全的
return instance;
}
};三、對比表格
| 特性 | 餓漢模式 | 傳統(tǒng)飽漢模式(雙檢鎖) | C++11靜態(tài)局部變量 |
|---|---|---|---|
| 創(chuàng)建時(shí)機(jī) | 程序啟動(dòng)時(shí) (main函數(shù)之前) | 第一次調(diào)用 getInstance() 時(shí) | 第一次調(diào)用 getInstance() 時(shí) |
| 線程安全 | ? 天然線程安全 (靜態(tài)初始化階段) | ? 需要雙檢鎖等機(jī)制 (手動(dòng)實(shí)現(xiàn)) | ? 編譯器保證線程安全 (C++11標(biāo)準(zhǔn)規(guī)定) |
| 資源占用 | ? 啟動(dòng)即占用內(nèi)存 (即使不用) | ? 使用時(shí)才占用內(nèi)存 | ? 使用時(shí)才占用內(nèi)存 |
| 啟動(dòng)速度 | ?? 可能較慢 (如果構(gòu)造復(fù)雜) | ? 啟動(dòng)快 | ? 啟動(dòng)快 |
| 實(shí)現(xiàn)復(fù)雜度 | ? 簡單 | ? 復(fù)雜 (需正確實(shí)現(xiàn)雙檢鎖) | ? 非常簡潔 (一行代碼) |
| 性能開銷 | ? 調(diào)用無鎖開銷 | ?? 有鎖檢查開銷 (即使已初始化) | ? 幾乎無開銷 (編譯器優(yōu)化) |
| 銷毀控制 | ? 需手動(dòng)管理 | ? 需手動(dòng)管理 | ? 自動(dòng)管理 (程序結(jié)束時(shí)) |
| C++版本要求 | C++98 | C++98(需要鎖) C++11(原子操作) | C++11及以上 |
| 內(nèi)存泄漏風(fēng)險(xiǎn) | ?? 需正確釋放 | ?? 需正確釋放 | ? 無泄漏風(fēng)險(xiǎn) |
| 代碼示例 | cpp<br>static T* instance = new T();<br> | cpp<br>if (!instance) {<br> lock();<br> if (!instance) {<br> instance = new T();<br> }<br>}<br> | cpp<br>static T instance;<br>return instance;<br> |
| 適用場景 | 1. 實(shí)例小、構(gòu)造簡單 2. 程序必用 3. 多線程環(huán)境 4. C++98項(xiàng)目 | 1. 實(shí)例大、構(gòu)造復(fù)雜 2. 可能不用 3. C++98項(xiàng)目 4. 需要延遲初始化 | 絕大多數(shù)場景 1. C++11+項(xiàng)目 2. 需要延遲初始化 3. 要求代碼簡潔 4. 需要自動(dòng)清理 |
性能對比數(shù)據(jù)
| 操作 | 餓漢模式 | 雙檢鎖飽漢 | C++11靜態(tài)局部變量 |
|---|---|---|---|
| 第一次調(diào)用 | 0-10 ns | 50-100 ns | 20-50 ns |
| 后續(xù)調(diào)用 | 0-5 ns | 10-20 ns | 0-5 ns |
| 內(nèi)存占用 | 立即占用 | 延遲占用 | 延遲占用 |
| 線程競爭 | 無競爭 | 有鎖競爭 | 首次有競爭,后續(xù)無 |
四、選擇建議
使用餓漢模式當(dāng):
- 單例對象小,構(gòu)造簡單
- 程序運(yùn)行期間一定會(huì)用到
- 對性能要求高,希望無鎖訪問
- 多線程環(huán)境下不想處理同步問題
使用飽漢模式當(dāng):
- 單例對象大,構(gòu)造復(fù)雜或耗時(shí)
- 可能整個(gè)程序都不會(huì)用到該實(shí)例
- 對啟動(dòng)速度有要求
- 使用 C++11 或以上版本(可用靜態(tài)局部變量)
到此這篇關(guān)于C++ 單例模式兩種實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)C++ 單例模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++ Zlib庫封裝MyZip壓縮類的詳細(xì)過程
在軟件開發(fā)中,文件的壓縮和解壓縮是一項(xiàng)常見的任務(wù),而ZIP是一種被廣泛應(yīng)用的壓縮格式,本文將聚焦于一個(gè)簡化的C++實(shí)現(xiàn),通過分析代碼,我們將深入了解其設(shè)計(jì)和實(shí)現(xiàn)細(xì)節(jié),感興趣的朋友一起看看吧2023-11-11
vscode 配置 C/C++編譯環(huán)境(完整教程)
這篇文章主要介紹了vscode 配置 C/C++編譯環(huán)境(完整教程),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
C語言實(shí)現(xiàn)大數(shù)值金額大寫轉(zhuǎn)換的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)大數(shù)值金額大寫轉(zhuǎn)換的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-03-03

