單例模式詳細講解

一.定義

????????單例模式是一種創建型設計模式,確保一個類只有一個實例,并提供一個全局訪問點

特點:

1.構造函數和析構函數私有化

2.禁用拷貝構造函數和賦值運算符重載(=delete)

3.利用靜態成員函數和靜態成員變量來給外界提供訪問

二.惡漢式

? ? ? ?惡漢是非常霸道的,由此可見,對于惡漢式,我們程序加載時立即創建單例實例(無論是否需要)

代碼如下:

//惡漢式:
class Singleton 
{
public://利用靜態成員函數和靜態成員變量來給外界提供訪問static Singleton GetInstance(){return _instance;}	//禁用拷貝構造和賦值運算符Singleton(const Singleton&) =delete;Singleton& operator=(const Singleton&)=delete;
priavte://構造析構私有化:Singleton(){}~Singleton(){}static Singleton _instance;//定義一個對象 
};
//static類外實例化:
Singleton Singleton::_instance;

優點:

  • 線程安全(C++11保證靜態變量的線程安全初始化)

  • 程序啟動時就創建實例

  • 簡單直接

缺點:? ? ?

  • 本質是通過空間換來的,可能導致空間浪費

三.懶漢式

????????懶漢本質在于懶,說明只有當我們需要時才會創建單例對象,具有延遲實例化特點,通過調用GetInstance()函數來創建對象

優點;

按需創建對象,避免浪費空間

缺點:

基礎實現是非線程安全的,需額外處理多線程問題

下面我們一一來講解不同版本:

//懶漢式:
//初始版本--1
class Singleton
{
public:static Singleton* GetInstance(){if(nullptr==_instance){//創建對象_instance =new Singleton;}return _instance;}//禁用拷貝構造和賦值運算符Singleton(const Singleton&) =delete;Singleton& operator=(const Singleton&)=delete;
priavte://構造析構私有化:Singleton(){}~Singleton(){}static Singleton* _instance;//定義一個對象指針 
};
//類對象實例化: 
Singleton* Singleton::_instance=nullptr;

該版本問題如下:

該代碼不是線程、進程安全的,具體是指如果多個線程同時調用到GetInstance中的if語句且都進入,就會new兩個以上對象,無法確保只有一個類對象

解決方法:加鎖

//懶漢式:
//初始版本--2
#include <mutex>
class Singleton
{
public:static Singleton* GetInstance(){//單檢測法: _mutex.lock();if(nullptr==_instance){//創建對象_instance =new Singleton;}_mutex.unlock();return _instance;}//禁用拷貝構造和賦值運算符Singleton(const Singleton&) =delete;Singleton& operator=(const Singleton&)=delete;
priavte://構造析構私有化:Singleton(){}~Singleton(){}static Singleton* _instance;//定義一個對象指針static std::mutex _mutex; 
};
//類對象實例化: 
Singleton* Singleton::_instance=nullptr;
std::mutex Singleton::_mutex;

上面我們利用C++中提供的鎖解決了多線程問題,但是如果每次訪問都要加鎖,并且多線程訪問只有一個能夠進去,其他要等待,性能非常不好

下面我們來利用雙檢測法來解決問題:

//懶漢式:
//初始版本--3
#include <mutex>
class Singleton
{
public:static Singleton* GetInstance(){//雙檢測法: if(nullptr==_instance){_mutex.lock();if(nullptr==_instance){//創建對象 _instance =new Singleton;}_mutex.unlock();}return _instance;}//禁用拷貝構造和賦值運算符Singleton(const Singleton&) =delete;Singleton& operator=(const Singleton&)=delete;
priavte://構造析構私有化:Singleton(){}~Singleton(){}static Singleton* _instance;//定義一個對象指針static std::mutex _mutex; 
};
//類對象實例化: 
Singleton* Singleton::_instance=nullptr;
std::mutex Singleton::_mutex;

該雙檢測法并非是正確的雙檢測法,原因:如果CPU執行new的指令發生問題,即如果先返回對象指針,這樣就會接受到一個nullptr的指針,出現問題

newCPU執行過程;

1.分配空間 malloc

2.調用構造函數 (類)

3.返回對象指針

下面我們來學習正確的雙檢測法;

//懶漢式:
//初始版本--4
#include <mutex>
#include <atmoic>
class Singleton
{
public:static Singleton* GetInstance(){//雙檢測法: (正確寫法)Singleton* tmp = _instance.load(std::memory_order_relaxed);//std::memory_order_relaxed---C++11 引入,最寬松的內存順序約束,僅保證原子性,不提供線程間的同步或順序保證std::atomic_thread_fence(std::memory_order_acquire); if(nullptr==_instance){_mutex.lock();tmp = _instance.load(std::memory_order_relaxed);if (tmp == nullptr) {tmp = new Singleton();std::atomic_thread_fence(std::memory_order_release);_instance.store(tmp, std::memory_order_relaxed);}_mutex.unlock();}return tmp;}//禁用拷貝構造和賦值運算符Singleton(const Singleton&) =delete;Singleton& operator=(const Singleton&)=delete;
priavte://構造析構私有化:Singleton(){}~Singleton(){}static std::atomic<Singleton*> _instance;;//定義一個對象指針static std::mutex _mutex; 
};
//類對象實例化: 
std::atomic<Singleton*> Singleton::_instance(nullptr);
std::mutex Singleton::_mutex;

利用Atomic來保證原子性,保證雙檢測不會受到CPU執行指令順序影響

優點:

線程安全,高性能(只有第一次需要加鎖)

缺點:

實現復雜,需要注意內存屏障

最后,我們來學習發明單例模式的作者是如何寫的:

//作者實現的: 
class Singleton 
{
public:static Singleton& getInstance() {static Singleton instance;return instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;private:Singleton() {}~Singleton() {}
};

特點;

線程安全(C++11保證局部靜態變量的線程安全初始化)

延遲初始化

簡潔高效

不需要考慮內存釋放問題

只能說不愧是大佬!!!)

其實我們也可以考慮下智能指針和call_once來實現,大家可以試試

最后,感謝你的瀏覽,點個關注吧!!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90005.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90005.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90005.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

KORGym:評估大語言模型推理能力的動態游戲平臺

KORGym&#xff1a;評估大語言模型推理能力的動態游戲平臺 現有評估基準多受領域限制或 pretraining 數據影響&#xff0c;難以精準測LLMs內在推理能力。KORGym平臺應運而生&#xff0c;含50余款游戲&#xff0c;多維度評估&#xff0c;本文將深入解析其設計、框架、實驗及發現…

ISPDiffuser文章翻譯理解

ISPDiffuser: Learning RAW-to-sRGB Mappings with Texture-Aware Diffusion Models and Histogram-Guided Color Consistency翻譯 Type: Conference paper Author: Yang Ren1,4, Hai Jiang1,4, Menglong Yang1,2,?, Wei Li1,2, Shuaicheng Liu3,4,? Select: ???????…

C++線程池執行步驟分析,總結線程池流程

線程池流程總結&#xff1a;1、構造函數中創建線程&#xff0c;并添加到線程池&#xff08;構造函數返回時&#xff0c;線程自動啟動&#xff0c;并停在等待wait&#xff1a;從線程池取出一個任務處&#xff09;&#xff1b; 2、主線程中添加任務&#xff0c;到任務隊列。并用“…

Java 通過 HttpURLConnection發送 http 請求

問題&#xff1a; 在調試 kill 接口的時候&#xff0c;對方的服務用的是 Django RestFramework 框架提供的接口&#xff0c;用 python 請求時得到的內容如下&#xff1a; ? ~ python3 test.py <Response [200]> "true" // 對應的代碼是 print(response, r…

【PTA數據結構 | C語言版】列出連通集

本專欄持續輸出數據結構題目集&#xff0c;歡迎訂閱。 文章目錄題目代碼題目 給定一個有 n 個頂點和 m 條邊的無向圖&#xff0c;請用深度優先遍歷&#xff08;DFS&#xff09;和廣度優先遍歷&#xff08;BFS&#xff09;分別列出其所有的連通集。假設頂點從 0 到 n?1 編號。…

GoLang教程005:switch分支

3.4 Switch分支 在 GoLand&#xff08;其實是 JetBrains 開發的 Go 編程語言 IDE&#xff09;中&#xff0c;switch 是 Go 語言&#xff08;Golang&#xff09; 的一個重要控制結構&#xff0c;用于替代多個 if-else 語句。 ? 特點說明特性說明自動 breakGo 的 switch 語句默認…

uniapp相關地圖 API調用

目錄 一、 注意事項&#xff1a; manifest.json需增加配置 二、獲取用戶收貨地址 [uni.chooseAddress] 三、獲取當前的地理位置、速度 [uni.getLocation] 四、打開地圖選擇位置、查看位置(導航) [uni.chooseLocation] [uni.openLocation] 五、使用騰訊地圖逆地址解析接口實…

Java學習----NIO模型

在 Java 的 I/O 模型中&#xff0c;NIO&#xff08;Non - Blocking I/O&#xff0c;非阻塞 I/O&#xff09;是對 BIO 的重要改進。它為高并發場景提供了更高效的處理方式&#xff0c;在眾多 Java 應用中發揮著關鍵作用。NIO模型的核心在于非阻塞和多路復用&#xff0c;其采用 “…

MySQL計數函數count原理分析

前言 統計表中數據的條數是非常常用的操作,但是咱們常用的InnoDB存儲引擎計數函數是現時統計的,所以會出現性能的問題,這次我準備分享計數函數count的原理,保證之后遇到計數方面的問題都可以輕易靈活的解決 與MyISAM存儲引擎相比,MyISAM存儲引擎是自己記錄了表中數據的條數,但…

Day07_網絡編程20250721_大項目

基本代碼&#xff1a;搭建服務器客戶端&#xff0c;要求服務器使用 epoll 模型客戶端使用多線程服務器打開數據庫&#xff0c;表單格式如下name text primary key pswd text not null客戶端做一個簡單的界面&#xff1a;1&#xff1a;注冊2&#xff1a;登錄無論注冊還是登錄&am…

20250721

P5357 【模板】AC 自動機 - 洛谷 主要是構建fail樹 /* 我們可以知道的是&#xff0c;當訪問一個點x時&#xff0c;接下來需要跳轉其fail[x]&#xff0c;以此類推&#xff0c;如果在某個fail[x]上出現了一個字符串&#xff0c;那么相應的統計次數應該加1&#xff0c;然后當訪…

【INT四則優先算式】2022-9-22

緣由ccf201903-2二十四點我用暴力破解做的&#xff0c;但是兩個程序一個拿到了滿分&#xff0c;一個拿到了50分&#xff0c;看了很長時間也沒看出問題在哪里&#xff0c;希望有英雄慧眼幫我看一下-編程語言-CSDN問答 void INT四則優先算式() {//緣由https://ask.csdn.net/ques…

本地k8s集群的搭建

windows機器&#xff0c;考慮如果使用云服務器&#xff0c;每年的開銷還是太大&#xff0c;不值得&#xff0c;自己只是做demo&#xff0c;了解各種配置和使用即可&#xff0c;使用VMware的虛擬機來搭建k8s集群 使用docker安裝rancher和k8s yum -y install chronycat > /et…

B樹、B+樹的區別及MySQL為何選擇B+樹

B樹與B樹 B樹和B樹都是自平衡的多路搜索樹&#xff0c;廣泛應用于數據庫和文件系統中&#xff0c;用于高效管理大量數據。它們的設計目標是在磁盤存儲環境下減少I/O操作次數&#xff0c;提高數據訪問效率。下面我將逐步解釋兩者的定義、特性、比較以及應用場景&#xff0c;確保…

Unity之可視化編程VisualScripting快速入門

文章目錄 前言 腳本機和狀態機 腳本圖ScriptGraph 腳本圖 子圖 自定義事件 狀態圖StateGraph 狀態圖 Start狀態 創建新狀態 過渡連接 常用功能 射線檢測 補間動畫 按鈕點擊 前言 可視化腳本使您無需編寫代碼即可為游戲或應用程序創建邏輯。可視化腳本使用基于節點的可視化圖形…

2025三掌柜贈書活動第二十五期 網絡安全應急響應實戰

目錄 前言 網絡安全的重要性 關于《網絡安全應急響應實戰》 編輯推薦 內容簡介 作者簡介 圖書目錄 《網絡安全應急響應實戰》全書速覽 結束語 前言 在當今數字化時代&#xff0c;網絡安全已經成為企業和個人都無法忽視的重要問題。隨著網絡技術的飛速發展&#xff0c;…

車載軟件架構 --- 軟件開發面臨的問題

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 周末洗了一個澡,換了一身衣服,出了門卻不知道去哪兒,不知道去找誰,漫無目的走著,大概這就是成年人最深的孤獨吧! 舊人不知我近況,新人不知我過…

MySQL 8.0 OCP 1Z0-908 題目解析(31)

題目121 Choose two. Examine this command, which executes successfully on InnoDB Cluster: dba.dropMetadataSchema() Which two statements are true? □ A) The mysql_innodb_cluster_metadata schema is dropped from the instance where the connection was establish…

本地生活服務 app 同城信息發布系統搭建

一、邏輯分析用戶需求層面&#xff1a;對于發布者來說&#xff0c;需要一個便捷的界面來輸入同城信息&#xff0c;包括但不限于房屋租售、招聘求職、二手交易、活動推廣等各類信息。發布者要能夠上傳相關圖片、詳細描述信息內容、設置價格&#xff08;如果有需要&#xff09;、…

[Python] -項目實戰4- 利用Python進行Excel批量處理

一、為什么要批量處理Excel文件? 節省時間:人工對數十、數百個 Excel 文件重復操作不現實,Python 批量處理一次搞定。 保證一致性:統一格式、統一操作,避免手動誤差。 易于集成:可嵌入日常自動化流程,支持定時和觸發執行。 二、常用庫及選型建議 庫 作用 優勢 局限 p…