單例模式的c++實現

来源:http://www.cnblogs.com/suntp/archive/2017/02/20/6421508.html
-Advertisement-
Play Games

單例模式的c++實現 ...


  1 #pragma once
  2 
  3 #include <iostream>
  4 #include <memory>
  5 #include <Windows.h>
  6 using namespace std;
  7 /***************************************************************************************
  8 
  9 1、首先要有一個創建實例的靜態函數GetInstance
 10 2、實現的方式既可以通過new動態創建,也可以通過static靜態局部變數實現
 11 3、創建的時機既可以通過靜態變數初始化時創建,也可以在調用GetInstance函數時再創建,通過靜態變數的初始化的好處是
 12 它是在進入主函數之前創建成功的可以避免多線程的問題,但是壞處就是在程式啟動時初始化會拖慢啟動過程。
 13 4、為了防止通過調用構造函數創建實例,要將類的構造、複製構造和賦值構造函數設為私有的
 14 5、GetInstance函數的返回值既可以是指針,又可以是引用,當是指針的時候要防止它在中途被delete掉,因此要將析構函數設為私有的
 15 6、這種模式有點像全局變數,但還是有區別的,單件的作用是保證只有一份實例,而能夠全局訪問是它附帶的功能。
 16 
 17 ********************************************************//////////////////////////////////////
 18 class singleton1
 19 {
 20 public:
 21     static singleton1* GetInstance()
 22     {
 23         if(ptr == NULL)
 24             ptr = new singleton1;
 25         return ptr;
 26     }
 27 
 28     static void show()
 29     {
 30         cout << "singleton1::show" << endl;
 31     }
 32 
 33 private:
 34     ~singleton1()
 35     {
 36         cout << "dest singleton1" << endl;
 37     }
 38     static singleton1* ptr;
 39     singleton1()
 40     {
 41         cout << "cstr singleton1" << endl;
 42     }
 43 
 44     singleton1(const singleton1 &);
 45     singleton1& operator=(const singleton1 &);
 46 };
 47 
 48 singleton1* singleton1::ptr = new singleton1;
 49 
 50 /*****************
 51 1、在上面的實現中,使用指針時,不能銷毀實例,只有當程式結束時才由系統回收,考慮將指針設計成智能指針shared_ptr,
 52 但是智能指針的回收還是要調用析構函數,聲明為public,指針隨時會被delete,有很多問題,所以這種方法是不太實用
 53 *****************/
 54 class singleton3
 55 {
 56 public:
 57     ~singleton3()
 58     {
 59         cout << "dest singleton3" << endl;
 60     }
 61 
 62     static singleton3* GetInstance()
 63     {
 64         if(ptr.get() == NULL)
 65             ptr.reset(new singleton3);
 66         return ptr.get();
 67     }
 68 
 69     static void show()
 70     {
 71         cout << "singleton3::show" << endl;
 72     }
 73 
 74 private:
 75     static shared_ptr<singleton3> ptr;
 76     singleton3(){}
 77     singleton3(const singleton3 &);
 78     singleton3& operator=(const singleton3 &);
 79 };
 80 
 81 shared_ptr<singleton3> singleton3::ptr;
 82 
 83 /****************************************
 84 1、上面的實現都是基於new動態創建,並且返回的都是指針類型,這個實現基於靜態局部變數,並且返回引用類型
 85 2、返回引用而不是指針的好處是,不用擔心中間會被delete掉
 86 3、採用靜態局部變數的好處是,記憶體管理交給系統,不需要手動管理
 87 ****************************************/
 88 class singleton4
 89 {
 90 public:
 91     ~singleton4()
 92     {
 93         cout << "dest singleton4" << endl;
 94     }
 95 
 96     static singleton4& GetInstance()
 97     {
 98         static singleton4 s;
 99         return s;
100     }
101 
102     static void show()
103     {
104         cout << "singleton4::show" << endl;
105     }
106 
107 private:
108     singleton4(){;}
109     singleton4(const singleton4 &);
110     singleton4& operator=(const singleton4 &);
111 };
112 
113 /***************************
114 1、如果是在GetInstance函數中創建實例,並且是多線程的話,如果有多個線程同時調用該函數,
115 則可能會創建多個實例,所以要對創建過程進行加鎖處理
116 **************************/
117 CRITICAL_SECTION g_cs;
118 class Lock
119 {
120 public:
121     Lock()
122     {
123         InitializeCriticalSection(&g_cs);
124     }
125 
126     void LockOn()
127     {
128         EnterCriticalSection(&g_cs);
129     }
130 
131     void LockOff()
132     {
133         LeaveCriticalSection(&g_cs);
134     }
135 
136     ~Lock()
137     {
138         DeleteCriticalSection(&g_cs);
139     }
140 };
141 Lock g_lock;
142 
143 class singleton5
144 {
145 public:
146     ~singleton5()
147     {
148         cout << "dest singleton5" << endl;
149     }
150 
151     static singleton5* GetInstance()
152     {
153         if(ptr == NULL)
154         {
155             //採用雙重判斷是為了提高效率,防止每次都要執行加鎖過程
156             g_lock.LockOn();
157             if(ptr == NULL)
158                 ptr = new singleton5;
159             g_lock.LockOff();
160         }
161 
162         return ptr;
163     }
164 
165     static void show()
166     {
167         cout << "singleton5::show" << endl;
168     }
169 
170 private:
171     static singleton5* ptr;
172     singleton5(){}
173     singleton5(const singleton5 &);
174     singleton5& operator=(const singleton5 &);
175 };
176 singleton5* singleton5::ptr = NULL;
177 
178 /******************
179 1、上面的實現雖然滿足了多線程調用,但是實際中可能會有很多類都要設計成實例模式,
180 那麼就需要都按照上面那樣實現一遍,不能重用,下麵的模板類就可以滿足重用的需求
181 *******************************/
182 template <typename T>
183 class Singleton
184 {
185 public:
186     static T& Instance()
187     {
188         if (m_pInstance == NULL)
189         {
190             //Lock lock;
191             g_lock.LockOn();
192             if (m_pInstance == NULL)
193             {
194                 m_pInstance = new T;
195                 atexit(&Destroy);//將Destroy註冊為程式結束時的執行函數釋放記憶體
196             }
197 
198             //return *m_pInstance;
199             g_lock.LockOff();
200         }
201 
202         return *m_pInstance;
203     }
204 
205 protected:
206     Singleton(void) 
207     {
208         cout << "cstr Singleton" << endl;
209     }
210     virtual ~Singleton(void) 
211     {
212         cout << "dest Singleton" << endl;
213     }
214 
215 private:
216     Singleton(const Singleton& rhs)
217     {
218         cout << "copy cstr Singleton" << endl;
219     }
220     Singleton& operator = (const Singleton& rhs) 
221     {
222         cout << "= cstr Singleton" << endl;
223     }
224 
225     static void Destroy()
226     {
227         if (m_pInstance != NULL)
228             delete m_pInstance;
229         m_pInstance = NULL;
230     }
231 
232     static T* m_pInstance;
233 };
234 
235 template <typename T>
236 T* Singleton<T>::m_pInstance = NULL;
237 
238 //實際的單例類就按照下麵的方式實現
239 class SingletonInstance : public Singleton<SingletonInstance>
240 {
241 public:
242     friend Singleton<SingletonInstance>;
243     void show()
244     {
245         cout << "SingletonInstance::show" << endl;
246     }
247 //
248 private:
249     SingletonInstance() 
250     {
251         cout << "cstr SingletonInstance" << endl;
252     }
253     virtual ~SingletonInstance(void) 
254     {
255         cout << "dest SingletonInstance" << endl;
256     }
257 
258     SingletonInstance(const SingletonInstance& rhs) 
259     {
260         cout << "copy cstr SingletonInstance" << endl;
261     }
262 };
263 
264 //測試類
265 class SingletonTest
266 {
267 public:
268     SingletonTest()
269     {
270         //singleton1& s1 = singleton1::GetInstance1();
271         //s1.show();
272 
273         //singleton1 *p1 = singleton1::GetInstance();
274         //p1->show();
275         ////delete p1;
276 
277         //singleton3 *p3 = singleton3::GetInstance();
278         //p3->show();
279 
280         //singleton4 &p4 = singleton4::GetInstance();
281         //p4.show();
282 
283         //singleton5 *p5 = singleton5::GetInstance();
284         //p5->show();
285 
286         SingletonInstance &si = SingletonInstance::Instance();
287         si.show();
288     }
289 };

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在面向對象軟體開發過程中,一些有經驗的軟體開發人員通常會採用設計模式來解決一些日常工作中的一些問題。設計模式是前人在軟體開發的過程中總結出來的一些解決問題的方案,並且經受住了時間的考驗和廣大軟體開發人員的不斷驗證。在軟體開發過程中,如果我們合理的使用設計模式可以提高代碼的復用性和可維護性。為了保證引 ...
  • 封裝矩形構造函數,扇形構造函數 ...
  • 前言 筆者最近在負責某集團網站時,同時用到了Nginx與F5,如圖所示,負載均衡器F5作為處理外界請求的第一道“牆”,將請求分發到web伺服器後,web伺服器上的Nginx再進行處理,靜態內容直接訪問本地門戶,動態數據則通過反向代理指向內網服務。 其實Nginx和F5這兩者均可用作網站負載均衡,那二 ...
  • ...
  • 1. 許可權管理:點開二級菜單進入三級菜單顯示 角色(基礎許可權)和按鈕許可權 角色(基礎許可權): 分角色組和角色,獨立分配菜單許可權和增刪改查許可權。 按鈕許可權: 給角色分配按鈕許可權。2. 按鈕管理:自定義按鈕管理,維護按鈕許可權標識等3. 菜單管理:無限級別自定義菜單,自定義菜單圖標,業務菜單和系統菜單分離 ...
  • Struts2類型轉換 struts2中內置了大量的類型轉換器用來完成數據類型轉換的問題,這篇隨筆主要通過兩個方面來寫Struts類型轉換 1:Struts2內置的類型轉換器 2:如何自定義類型轉換器 那麼首先我們來學習有關Struts2內置的類型 1:Struts2內置的類型轉換器 Struts2 ...
  • 早就發現java父類有個方法clone(),但一直沒用過,也不知道怎麼用。直到學習了原型設計模式才明白,他就是克隆方法,專門用來複制對象的。雖然到目前為止還沒真正在項目中用到,但克隆方法還是挺有用的,它為我們創建相同對象帶來了很大的便利,只要克隆一下就可以擁有一個全新的、初始值跟父類一樣的對象。 一 ...
  • 我們知道從applicationContext容器對象中如何獲取Bean了,其實spring框架還有另外一種獲取bean的方法:BeanFactory代碼如下: 那麼,兩者之間有啥區別呢? applicationContext 當我們使用applicationContext來獲取對象的時候,只要我們 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...