最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c語言設(shè)計(jì)模式之單例模式中的餓漢與懶漢詳解

 更新時(shí)間:2023年08月03日 09:17:36   作者:Pin_na  
這篇文章主要介紹了c語言設(shè)計(jì)模式之單例模式中的餓漢與懶漢詳解,單例模式是指一個類只能創(chuàng)建一個對象,保證系統(tǒng)中該類只有一個實(shí)例,并提供一個可供訪問的全局訪問點(diǎn),該實(shí)例被所有程序模塊共享,需要的朋友可以參考下

設(shè)計(jì)模式

設(shè)計(jì)模式是一套反復(fù)使用、多人知曉、經(jīng)過分類的代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。

如單例模式、工廠模式、觀察者模式等等。

單例模式

單例模式是指一個類只能創(chuàng)建一個對象,保證系統(tǒng)中該類只有一個實(shí)例,并提供一個可供訪問的全局訪問點(diǎn),該實(shí)例被所有程序模塊共享,其中單例模式又分為了餓漢模式和懶漢模式兩種實(shí)現(xiàn)方式。

應(yīng)用

  • 需要頻繁實(shí)例化然后銷毀的對象。 
  • 創(chuàng)建對象時(shí)耗時(shí)過多或者耗資源過多,但又經(jīng)常用到的對象。 
  • 有狀態(tài)的工具類對象。 
  • 頻繁訪問數(shù)據(jù)庫或文件的對象。

資源共享:

避免由于資源操作時(shí)導(dǎo)致的性能或損耗等。如日志文件,應(yīng)用配置等...

控制資源:

方便資源之間的互相通信。如線程池等...

實(shí)現(xiàn)

基本思想:

構(gòu)造函數(shù)為private私有屬性全局唯一公共訪問點(diǎn)來創(chuàng)建對象,函數(shù)為public屬性為了使用方便增加一個GC輔助類來釋放資源

餓漢模式

餓漢顧名思義就是很饑餓,迫不及待想吃東西,所以這種實(shí)現(xiàn)方式就是:無論以后對象會不會用到,程序一啟動時(shí)就創(chuàng)建一個唯一的實(shí)例對象

  • 優(yōu)點(diǎn):簡單,線程安全
  • 缺點(diǎn):可能導(dǎo)致進(jìn)程啟動慢、多個單例對象實(shí)例啟動順序不可控
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Singleton
{
public:
	//提供靜態(tài)公有方法,可以類名加域名訪問,返回對象指針
	static Singleton* GetInstance()
	{
		return m_instance;
	}
	class GCarbo
	{
	public:
		~GCarbo()
		{
			cout << "delete instance" << endl;
			if (nullptr != m_instance){
				delete Singleton::m_instance;
				m_instance = nullptr;
			}
		}
	};
private:
	//構(gòu)造函數(shù)私有
	Singleton(){
		cout << "Singleton" << endl;
	};
	//防拷貝
	//C++98
	//Singleton(Singleton const&);
	//Singleton& operator=(Singleton const&);
	//C++11
	Singleton(Singleton const&) = delete;
	Singleton& operator=(Singleton const&) = delete;
	static Singleton *m_instance;
	static GCarbo Carbo;
};
//在程序入口之前完成單例對象的初始化
Singleton* Singleton::m_instance = new Singleton;
Singleton::GCarbo Carbo;
int main()
{
	cout << "main begin" << endl;
	//均無法創(chuàng)建實(shí)例
	//Singleton s;
	//Singleton* p = new Singleton;
	//調(diào)用共有靜態(tài)成員方法
	Singleton* p1= Singleton::GetInstance();
	Singleton* p2 = Singleton::GetInstance();
	if (p1 == p2){
		cout << "yes" << endl;
	}
	else{
		cout << "no" << endl;
	}
	system("pause");
	return 0;
}

運(yùn)行結(jié)果:

整個程序運(yùn)行過程中只調(diào)用了一次構(gòu)造函數(shù),并且兩個對象為同一個對象,程序結(jié)束后自動銷毀對象  

懶漢模式

相反,懶漢模式就是已經(jīng)懶到極致了,單例實(shí)例當(dāng)首次被引用時(shí)才將進(jìn)行初始化,盡量使資源的利用最大化。如最常見的晚綁定、寫時(shí)拷貝技術(shù)都是這種實(shí)現(xiàn)方式。

  • 優(yōu)點(diǎn):進(jìn)程啟動無負(fù)載,多個單例實(shí)例啟動順序可控制
  • 缺點(diǎn):復(fù)雜,線程不安全

但是這里要注意一點(diǎn),不同于餓漢模式GetInstance全局公共訪問點(diǎn)僅僅返回一個類對象的指針,因?yàn)槲覀儾]有在類外實(shí)例化對象,所以我們要對對象的實(shí)例化進(jìn)行判斷,沒有對象時(shí)才能創(chuàng)建一個對象

static Singleton* GetInstance()
{
	if (nullptr == m_instance){
			m_instance = new Singleton();
	}
	return m_instance;
}

完整代碼如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Singleton
{
public:
	static Singleton* GetInstance()
	{
		if (nullptr == m_instance){
			m_instance = new Singleton();
		}
		return m_instance;
	}
	//內(nèi)嵌垃圾回收類
	class CGarbo{
	public:
   		~CGarbo(){
			cout << "delete instance" << endl;
			if (nullptr != Singleton::m_instance){
				delete Singleton::m_instance;
				m_instance = nullptr;
			}
		}
	};
	//定義一個靜態(tài)成員變量,程序結(jié)束后自動調(diào)用其析構(gòu)函數(shù)釋放單例對象
	static CGarbo Garbo;
private:
	//構(gòu)造函數(shù)私有
	Singleton() {
		printf("Singleton\n");
	};
	//防拷貝
	Singleton(Singleton const&);
	Singleton& operator=(Singleton const&);
	//單例對象指針
	static Singleton* m_instance;
};
Singleton* Singleton::m_instance = nullptr;
Singleton::CGarbo Garbo;
int main()
{
	cout << "main begin" << endl;
	cout << Singleton::GetInstance() << endl;
	cout << Singleton::GetInstance() << endl;
	system("pause");
	return 0;
}

運(yùn)行結(jié)果:

  

這樣寫看似就可以了,兩個實(shí)例也創(chuàng)建了相同的對象,真的就可以了嘛?答案是否定的,現(xiàn)在我們在多線程環(huán)境下在對這段代碼進(jìn)行演示

我們發(fā)現(xiàn),兩個線程竟然創(chuàng)建了兩個不同的對象出來,這顯然不符合我們單例模式的要求,為什么會出現(xiàn)這種原因呢,假如第一個線程剛剛判斷完 m_instance 為 nullptr 開始創(chuàng)建對象,對象還未創(chuàng)建完成,第二個線程也開始判斷,此時(shí)對象未創(chuàng)建完成,條件滿足,也會繼續(xù)執(zhí)行對象創(chuàng)建的代碼創(chuàng)建對象,所以創(chuàng)建出了兩個不同的對象出來。

可能的線程不安全情況舉例(數(shù)字表示按時(shí)間片程序的執(zhí)行順序):

情況一(線程不安全):

情況二(編譯器自動優(yōu)化,進(jìn)行指令重排):

對于情況一解決辦法就是我們需要對創(chuàng)建對象的操作加互斥鎖,保證操作的原子性,由于加鎖后創(chuàng)建對象線程可能阻塞,所以這里我們?yōu)榱送瑫r(shí)保證效率和安全通常會選擇 Double-Check 方式加鎖

static Singleton* GetInstance()
	{
		//Double-Check方式加鎖保證效率和線程安全
		//保證效率
		if (nullptr == m_instance){
			//保證線程安全
			m_mtx.lock();
			//正常檢查
			if (nullptr == m_instance){
				m_instance = new Singleton();
			}
			m_mtx.unlock();
		}
		return m_instance;
	}

但是情況二顯然程序還會出現(xiàn)問題,我們在 m_instance 對象前加上 volatile即可,禁止編譯器優(yōu)化,將變量從內(nèi)存中讀取,而不是從寄存器中讀取。

整個懶漢模式的完整代碼:

class Singleton
{
public:
	static volatile Singleton* GetInstance()
	{
		//Double-Check方式加鎖保證效率和線程安全
		//保證效率
		if (nullptr == m_instance){
			//保證線程安全
			m_mtx.lock();
			//正常檢查
			if (nullptr == m_instance){
				m_instance = new Singleton();
			}
			m_mtx.unlock();
		}
		return m_instance;
	}
	//內(nèi)嵌垃圾回收類
	class CGarbo{
	public:
		~CGarbo(){
			cout << "delete instance" << endl;
			if (nullptr != Singleton::m_instance){
				delete Singleton::m_instance;
				m_instance = nullptr;
			}
		}
	};
	//定義一個靜態(tài)成員變量,程序結(jié)束后自動調(diào)用其析構(gòu)函數(shù)釋放單例對象
	static CGarbo Garbo;
private:
	//構(gòu)造函數(shù)私有
	Singleton() {
		//cout原型operator <<() 連續(xù)的cout相當(dāng)于是函數(shù)的遞歸調(diào)用過程
		//cout.operator<<(c1);
		//由于線程的特性會導(dǎo)致輸出亂序
		printf("Singleton\n");
	};
	//防拷貝
	Singleton(Singleton const&);
	Singleton& operator=(Singleton const&);
	//單例對象指針
	static volatile Singleton* m_instance;
	static mutex m_mtx;
};
volatile Singleton* Singleton::m_instance = nullptr;
Singleton::CGarbo Garbo;
mutex Singleton::m_mtx;
void func(int n)
{
	printf("%d: %p\n", n, Singleton::GetInstance());
	//cout << Singleton::GetInstance() << " " << n << endl;
}
int main()
{
	cout << "main begin" << endl;
	thread t1(func, 1);
	thread t2(func, 2);
	t1.join();
	t2.join();
	printf("%p\n", Singleton::GetInstance());
	printf("%p\n", Singleton::GetInstance());
	system("pause");
	return 0;
}

結(jié)果完全沒有問題:

到此這篇關(guān)于c語言設(shè)計(jì)模式之單例模式中的餓漢與懶漢詳解的文章就介紹到這了,更多相關(guān)c語言單例模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 用C語言簡單實(shí)現(xiàn)掃雷小游戲

    用C語言簡單實(shí)現(xiàn)掃雷小游戲

    這篇文章主要為大家詳細(xì)介紹了用C語言簡單實(shí)現(xiàn)掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • C++中char*轉(zhuǎn)換為LPCWSTR的解決方案

    C++中char*轉(zhuǎn)換為LPCWSTR的解決方案

    最近在學(xué)習(xí)C++,遇到了一個char*轉(zhuǎn)換為LPCWSTR的問題,通過查找資料終于解決了,所以下面這篇文章主要介紹了C++中char*轉(zhuǎn)LPCWSTR的解決方案,文中通過詳細(xì)的示例代碼介紹的很詳細(xì),有需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-01-01
  • C++中的Reactor原理與實(shí)現(xiàn)

    C++中的Reactor原理與實(shí)現(xiàn)

    reactor設(shè)計(jì)模式是event-driven?architecture的一種實(shí)現(xiàn)方式,處理多個客戶端并發(fā)的向服務(wù)端請求服務(wù)的場景,每種服務(wù)在服務(wù)端可能由多個方法組成,這篇文章主要介紹了Reactor原理與實(shí)現(xiàn),需要的朋友可以參考下
    2022-07-07
  • C++小知識:不要去做編譯器的工作

    C++小知識:不要去做編譯器的工作

    今天小編就為大家分享一篇關(guān)于C++小知識:不要去做編譯器的工作,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • 基于Windows API分解路徑問題的詳解

    基于Windows API分解路徑問題的詳解

    本篇文章是對Windows API分解路徑進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 關(guān)于C++中數(shù)據(jù)16進(jìn)制輸出的方法

    關(guān)于C++中數(shù)據(jù)16進(jìn)制輸出的方法

    本文主要介紹了關(guān)于C++中數(shù)據(jù)16進(jìn)制輸出的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 探討C++中數(shù)組名與指針的用法比較分析

    探討C++中數(shù)組名與指針的用法比較分析

    本篇文章是對C++中數(shù)組名與指針用法的比較進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++ 并發(fā)與多線程編程全面解析

    C++ 并發(fā)與多線程編程全面解析

    本文給大家介紹C++并發(fā)與多線程編程全面解析,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2025-08-08
  • C++拷貝構(gòu)造函數(shù)中的陷阱

    C++拷貝構(gòu)造函數(shù)中的陷阱

    這篇文章主要介紹了C++拷貝構(gòu)造函數(shù)中的陷阱,拷貝構(gòu)造函數(shù)大家都比較熟悉,通俗講就是傳入一個對象,拷貝一份副本。不過看似簡單的東西,實(shí)際不注意的話就會產(chǎn)生問題,下面我們就來看看C++拷貝構(gòu)造函數(shù)中都有哪些陷阱吧
    2022-01-01
  • C++實(shí)現(xiàn)時(shí)間轉(zhuǎn)換及格式化

    C++實(shí)現(xiàn)時(shí)間轉(zhuǎn)換及格式化

    這篇文章主要為大家詳細(xì)介紹了C++中實(shí)現(xiàn)時(shí)間轉(zhuǎn)換及格式化的相關(guān)知識,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11

最新評論

荃湾区| 余江县| 龙泉市| 多伦县| 牟定县| 香港| 怀化市| 治多县| 雅江县| 三台县| 夏津县| 宝鸡市| 庐江县| 玛多县| 新和县| 胶南市| 突泉县| 澜沧| 炉霍县| 连平县| 剑阁县| 梓潼县| 望江县| 英德市| 太保市| 黔西| 阿拉善右旗| 张北县| 黄骅市| 将乐县| 册亨县| 同江市| 双辽市| 南皮县| 年辖:市辖区| 加查县| 黄石市| 阿拉善右旗| 泽库县| 余干县| 公主岭市|