首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C++ 設計模式:單例模式四大實作版本演進與執行緒安全、效能、銷毀時機完整對比

     編輯:關於C語言

單例模式確保類別僅有一實例並提供全域存取點。本文針對日誌模組需求,演示四種主流實作版本:基本版、雙重檢查鎖版、靜態初始化版、區域靜態變數版,深度對比執行緒安全、效能、銷毀控制與適用場景。

問題背景

  • 系統需全域日誌模組,任何位置可呼叫寫日誌。
  • 全域變數違反封裝、多執行緒不安全、初始化順序不定(跨編譯單元)。
  • 單例模式:私有建構函數 + 靜態工廠方法回傳唯一實例。

版本一:基本版(非執行緒安全)

class Singleton {
    static Singleton *m_instance;
    int m_test;
    Singleton() : m_test(10) {}
public:
    static Singleton* GetInstance() {
        if (!m_instance) m_instance = new Singleton();
        return m_instance;
    }
    static void DestroyInstance() {
        delete m_instance; m_instance = nullptr;
    }
    int GetTest() { return m_test; }
};
Singleton* Singleton::m_instance = nullptr;

❌ 多執行緒下可能建立多個實例。

版本二:雙重檢查鎖


static Singleton* GetInstance() {
    if (!m_instance) {
        Lock();  // 需外部庫(Boost/std::mutex)
        if (!m_instance) m_instance = new Singleton();
        UnLock();
    }
    return m_instance;
}

✅ 執行緒安全(雙重檢查減少鎖開銷)。
⚠️ 高併發下鎖競爭成為效能瓶頸。
⚠️ 需手動呼叫 DestroyInstance(),易忘記/時機難控。

版本三:靜態初始化(鴨子模式)


class Singleton {
    int m_test;
    Singleton() : m_test(10) {}
public:
    static Singleton* GetInstance() {
        return const_cast<Singleton*>(m_instance);
    }
    static void DestroyInstance() { /* 同版本一 */ }
private:
    static const Singleton *m_instance;
};
const Singleton* Singleton::m_instance = new Singleton();  // 主執行緒單執行緒初始化

✅ 靜態初始化發生在 main 前,主執行緒單執行緒完成,**天然執行緒安全**。
✅ 無鎖開銷,效能最佳。
⚠️ 實例建立時間提前(程式啟動時),若建構耗時影響啟動速度。
⚠️ 同樣需手動銷毀。

版本四:區域靜態變數(Meyers Singleton,C++11 保證執行緒安全)


class Singleton {
    int m_test;
    Singleton() : m_test(10) {}
    ~Singleton() { cout << "Singleton destroyed" << endl; }
public:
    static Singleton* GetInstance() {
        static Singleton instance;  // C++11 保證執行緒安全初始化
        return &instance;
    }
    int GetTest() { return m_test++; }
    // 無 DestroyInstance,由程式結束自動解構
};

✅ C++11 標準保證**執行緒安全初始化**(魔術靜態)。
✅ **首次使用時才建構**(Lazy Initialization),不影響啟動速度。
✅ **自動銷毀**(程式結束時按逆序解構),無記憶體洩漏風險。
✅ 程式碼最簡潔,現代 C++ **首選實作**。

四版本綜合對比

維度基本版雙重檢查鎖靜態初始化區域靜態 (C++11)
執行緒安全❌✅✅✅
同步開銷無首次有鎖無無
初始化時機首次呼叫首次呼叫程式啟動首次呼叫
銷毀控制手動手動手動自動
程式碼複雜度低中中極低
推薦等級❌⚠️ 旧專案⚠️ 特定需求✅✅✅ 標準

進階議題

  • 單例與測試:全域狀態難以隔離,建議依賴注入(傳遞介面指標)替代直接呼叫 GetInstance()。
  • 跨 DLL 邊界:每個 DLL 會有獨立靜態變數,需在共享庫中集中定義並匯出存取函式。
  • 遞迴初始化死結:單例建構過程中若間接呼叫自身 GetInstance(),C++11 會拋出例外(避免未定義行為)。

總結

現代 C++(C++11 及以上)請**直接使用區域靜態變數版本**(Meyers Singleton)。它同時解決執行緒安全、延遲初始化、自動銷毀、程式碼極簡四大痛點。舊專案維護時,按相容性選擇雙重檢查鎖或靜態初始化版本。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved