国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【C++】設(shè)計模式-單例模式

這篇具有很好參考價值的文章主要介紹了【C++】設(shè)計模式-單例模式。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

一、單例模式

單例模式的三個要點

針對上述三要點的解決方案

常用的兩類單例模式

?二、懶漢模式實現(xiàn)

1.基本實現(xiàn)

2.鎖+靜態(tài)成員析構(gòu)單例

3.雙層檢查鎖定優(yōu)化

4.雙層檢查鎖定+智能指針

三、餓漢模式實現(xiàn)

1.基礎(chǔ)實現(xiàn)

2.嵌套內(nèi)部類解決內(nèi)存泄漏

3.智能指針解決內(nèi)存泄漏?


一、單例模式

單例模式(Singleton Pattern)是 一種屬于創(chuàng)建型設(shè)計模式,它提供了一種創(chuàng)建對象的最佳方式。

這種模式涉及到一個單一的類,該類負(fù)責(zé)創(chuàng)建自己的對象,同時確保只有單個對象被創(chuàng)建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。(即它確保一個類只有一個實例,并提供了一個全局訪問點來訪問該實例。)

單例模式的三個要點

  • 1、單例類只能有一個實例。
  • 2、單例類必須自己創(chuàng)建自己的唯一實例。
  • 3、單例類必須給所有其他對象提供這一實例。

針對上述三要點的解決方案

1)私有化構(gòu)造函數(shù):這樣外界就無法自由地創(chuàng)建類對象,進(jìn)而阻止了多個實例的產(chǎn)生。

2)類定義中含有該類的唯一靜態(tài)私有對象:靜態(tài)變量存放在全局存儲區(qū),且是唯一的,供所有對象使用。

3)用公有的靜態(tài)函數(shù)來獲取該實例:提供了訪問接口。

常用的兩類單例模式

1)懶漢模式:在使用類對象(單例實例)時才會去創(chuàng)建它,不然就不創(chuàng)建。

2)餓漢模式:單例實例在類裝載時構(gòu)建,有可能全局都沒使用過,但它占用了空間,就像等著發(fā)救濟(jì)糧的餓漢提前排好隊等吃的一樣。


?二、懶漢模式實現(xiàn)

1.基本實現(xiàn)

//singleton.h
#pragma once
#include <iostream>
using namespace std;

class Singleton
{
public:
	//公共接口獲取唯一實例
	static Singleton* getInstance()
	{
		if (m_instance == nullptr)
		{
			cout << "創(chuàng)建實例" << endl;
			m_instance = new Singleton;
		}
		return m_instance;
	}
private:
	//構(gòu)造私有
	Singleton()
	{
		cout << "調(diào)用構(gòu)造函數(shù)" << endl;
	}  
	//Singleton()=default;


	~Singleton()
	{
		cout << "調(diào)用析構(gòu)函數(shù)" << endl;
	} 
	//~Singleton() = default;

	//禁用拷貝構(gòu)造和賦值運算符(=delete 為C++11新標(biāo)準(zhǔn))
	Singleton(Singleton const&) = delete;
	Singleton& operator=(Singleton const&) = delete;

private:
	//靜態(tài)私有對象
	static Singleton* m_instance;
};

Singleton* Singleton::m_instance = nullptr; //初始化
#include "singleton.h"

int main()
{
	Singleton* instance1 = Singleton::getInstance();
	Singleton* instance2 = Singleton::getInstance();
	return 0;

}

?執(zhí)行結(jié)果:

【C++】設(shè)計模式-單例模式,c++,設(shè)計模式,單例模式

由上述結(jié)果可知,的確只創(chuàng)建了一個實例。

但同時暴露了兩個問題:①線程安全;②內(nèi)存泄漏

①線程安全:在多線程場景下,可能多個線程進(jìn)行new操作,需要加鎖進(jìn)行限制,保證只進(jìn)行一次new操作。

【C++】設(shè)計模式-單例模式,c++,設(shè)計模式,單例模式

#include "singleton.h"

int main()
{
	thread t1([] {Singleton* s1 = Singleton::getInstance();});
	thread t2([] {Singleton* s2 = Singleton::getInstance();});

	t1.join();
	t2.join();
	return 0;

}

?【C++】設(shè)計模式-單例模式,c++,設(shè)計模式,單例模式

?②內(nèi)存泄漏:new在堆上的資源在程序結(jié)束時,需要通過delete進(jìn)行釋放。上面并沒有調(diào)用析構(gòu)函數(shù)執(zhí)行delete操作。

2.鎖+靜態(tài)成員析構(gòu)單例

#include <iostream>
#include <mutex>
using namespace std;

//鎖+靜態(tài)成員析構(gòu)單例
class Singleton
{
public:
	static Singleton* getInstance()
	{
		m_mutex.lock();//上鎖
		if (m_instance == nullptr)
		{
			cout << "創(chuàng)建實例" << endl;
			m_instance = new Singleton;
		}
		m_mutex.unlock();//解鎖
		return m_instance;
	}
private:
	Singleton()
	{
		cout << "調(diào)用構(gòu)造函數(shù)" << endl;
	}  
	//Singleton()=default;

	~Singleton()
	{
		cout << "調(diào)用析構(gòu)函數(shù)" << endl;
	} 
	//~Singleton() = default;

	Singleton(Singleton const&) = delete;
	Singleton& operator=(Singleton const&) = delete;

private:
	class FreeInstace
	{
	public:
		FreeInstace()=default;
		~FreeInstace()
		{
			if (Singleton::m_instance != nullptr)
			{
				delete Singleton::m_instance;
				cout << "單例銷毀" << endl;

			}
		}
	};
private:
	//靜態(tài)私有對象
	static Singleton* m_instance;
	static FreeInstace m_freeinstance;
	static mutex m_mutex;
};

Singleton* Singleton::m_instance = nullptr; //初始化
Singleton::FreeInstace Singleton::m_freeinstance;
mutex Singleton::m_mutex;

該方案的缺點在于對Singleton的每次訪問都需要獲取一個鎖,鎖導(dǎo)致速度慢,效率低。但實際上,我們只需要一個鎖,初始化m_instance時(即確定m_instance指向時),這應(yīng)該只在第一次調(diào)用實例時發(fā)生。如果在程序運行的過程中調(diào)用了n次instance,則只在第一次調(diào)用時需要鎖。當(dāng)你知道n - 1個鎖是不必要的,為什么還要為n個鎖的獲取買單呢?

3.雙層檢查鎖定優(yōu)化

static Singleton* getInstance()
	{
		if (m_instance == nullptr)
		{
			m_mutex.lock();//上鎖
			if (m_instance == nullptr)
			{
				cout << "創(chuàng)建實例" << endl;
				m_instance = new Singleton;
			}
			m_mutex.unlock();//解鎖
		}
		return m_instance;
	}

雙層檢查鎖定的關(guān)鍵是觀察到大多數(shù)對instance的調(diào)用將看到m_instance是非空的,因此不會嘗試初始化它。因此,它嘗試獲取鎖之前測試m_instance是否為空。只有當(dāng)測試成功(即m_instance尚未初始化)時,才會獲得鎖,然后再次執(zhí)行測試以確保m_instance仍然為空(因此稱為雙重檢查鎖定)。第二個測試是必要的,因為,正如上面描述的情況在m_instance第一次被測試到獲得鎖的時間之間,有可能發(fā)生另一個線程初始化m_instance的情況

使用雙層檢查鎖定將已經(jīng)初始化的對象的直接返回。可以使代碼性能會大大加快。但它們沒有考慮到一個更基本的問題,即確保在雙層檢查鎖定期間執(zhí)行的機器指令以可接受的順序執(zhí)行。

m_instance = new Singleton;

這個語句導(dǎo)致三件事發(fā)生:
步驟1:分配內(nèi)存來保存Singleton對象。
步驟2:在分配的內(nèi)存中構(gòu)造一個單例對象。
步驟3:使m_instance 指向已分配的內(nèi)存。
最重要的是觀察到編譯器不受約束,會按照這個順序執(zhí)行這些步驟!

特別是,編譯器有時允許交換步驟2和步驟3。所以可能導(dǎo)致訪問到未初始化的對象的引用。

解決方案:可以參考如下鏈接C++完美單例模式 - 簡書

4.雙層檢查鎖定+智能指針

針對內(nèi)存泄漏問題,除了可以方法2介紹的使用靜態(tài)成員在程序結(jié)束時,銷毀成員是調(diào)用析構(gòu)進(jìn)行delete,還可以使用智能指針,頭文件引用<memory>。

class Singleton
{
public:
	static shared_ptr<Singleton> getInstance()
	{
		if (m_instance == nullptr)
		{
			m_mutex.lock();//上鎖
			if (m_instance == nullptr)
			{
				cout << "創(chuàng)建實例" << endl;
				m_instance.reset( new Singleton(), destoryInstance);
			}
			m_mutex.unlock();//解鎖
		}
		return m_instance;
	}
	static void destoryInstance(Singleton* x) 
	{
		cout << "自定義釋放實例" << endl;
		delete x;
	}
private:
	Singleton()
	{
		cout << "調(diào)用構(gòu)造函數(shù)" << endl;
	}
	//Singleton()=default;

	~Singleton()
	{
		cout << "調(diào)用析構(gòu)函數(shù)" << endl;
	}
	//~Singleton() = default;

	Singleton(Singleton const&) = delete;
	Singleton& operator=(Singleton const&) = delete;

private:
	//靜態(tài)私有對象
	static  shared_ptr<Singleton> m_instance;
	static mutex m_mutex;
};

shared_ptr<Singleton> Singleton::m_instance = nullptr; //初始化
mutex Singleton::m_mutex;

應(yīng)用智能指針后,在程序結(jié)束時,它自動進(jìn)行資源的釋放,解決了內(nèi)存泄漏的問題。


三、餓漢模式實現(xiàn)

餓漢和懶漢的差別就在于,餓漢提前進(jìn)行了創(chuàng)建。

1.基礎(chǔ)實現(xiàn)

class Singleton
{
public:
	//公共接口獲取唯一實例
	static Singleton* getInstance()
	{
		return m_instance;
	}
private:
	//構(gòu)造私有
	Singleton()
	{
		cout << "調(diào)用構(gòu)造函數(shù)" << endl;
	}  
	//Singleton()=default;


	~Singleton()
	{
		cout << "調(diào)用析構(gòu)函數(shù)" << endl;
	} 
	//~Singleton() = default;

	//禁用拷貝構(gòu)造和賦值運算符(=delete 為C++11新標(biāo)準(zhǔn))
	Singleton(Singleton const&) = delete;
	Singleton& operator=(Singleton const&) = delete;

private:
	//靜態(tài)私有對象
	static Singleton* m_instance;
};

Singleton* Singleton::m_instance = new Singleton; //初始化

所以main還沒開始,實例就已經(jīng)構(gòu)建完畢。獲取實例的函數(shù)也不需要進(jìn)行判空操作,因此也就不用雙重檢測鎖來保證線程安全了,它本身已經(jīng)是線程安全狀態(tài)了。

但是內(nèi)存泄漏的問題還是要解決的。文章來源地址http://www.zghlxwxcb.cn/news/detail-591470.html

2.嵌套內(nèi)部類解決內(nèi)存泄漏

class Singleton
{
public:
	//公共接口獲取唯一實例
	static Singleton* getInstance()
	{
		return m_instance;
	}
private:
	//構(gòu)造私有
	Singleton()
	{
		cout << "調(diào)用構(gòu)造函數(shù)" << endl;
	}
	//Singleton()=default;


	~Singleton()
	{
		cout << "調(diào)用析構(gòu)函數(shù)" << endl;
	}
	//~Singleton() = default;

	//禁用拷貝構(gòu)造和賦值運算符(=delete 為C++11新標(biāo)準(zhǔn))
	Singleton(Singleton const&) = delete;
	Singleton& operator=(Singleton const&) = delete;

private:
	class FreeInstace
	{
	public:
		FreeInstace()=default;
		~FreeInstace()
		{
			if (Singleton::m_instance != nullptr)
			{
				delete Singleton::m_instance;
				cout << "單例銷毀" << endl;

			}
		}
	};
private:
	//靜態(tài)私有對象
	static Singleton* m_instance;
	static FreeInstace m_freeinstance;
};

Singleton* Singleton::m_instance = new Singleton; //初始化
Singleton::FreeInstace Singleton::m_freeinstance;

3.智能指針解決內(nèi)存泄漏?

class Singleton
{
public:
	//公共接口獲取唯一實例
	static shared_ptr<Singleton> getInstance()
	{
		return m_instance;
	}

	static void destoryInstance(Singleton* x) {
		cout << "自定義釋放實例" << endl;
		delete x;
	}
private:
	//構(gòu)造私有
	Singleton()
	{
		cout << "調(diào)用構(gòu)造函數(shù)" << endl;
	}  
	//Singleton()=default;


	~Singleton()
	{
		cout << "調(diào)用析構(gòu)函數(shù)" << endl;
	} 
	//~Singleton() = default;

	//禁用拷貝構(gòu)造和賦值運算符(=delete 為C++11新標(biāo)準(zhǔn))
	Singleton(Singleton const&) = delete;
	Singleton& operator=(Singleton const&) = delete;

private:
	//靜態(tài)私有對象
	static shared_ptr<Singleton> m_instance;
};

shared_ptr<Singleton>  Singleton::m_instance ( new Singleton, destoryInstance); //初始化

到了這里,關(guān)于【C++】設(shè)計模式-單例模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • C++設(shè)計模式創(chuàng)建型之單例模式

    一、概述 ? ? ? ? 單例模式也稱單態(tài)模式,是一種創(chuàng)建型模式,用于創(chuàng)建只能產(chǎn)生一個對象實例的類。例如,項目中只存在一個聲音管理系統(tǒng)、一個配置系統(tǒng)、一個文件管理系統(tǒng)、一個日志系統(tǒng)等,甚至如果吧整個Windows操作系統(tǒng)看成一個項目,那么其中只存在一個任務(wù)管理

    2024年02月14日
    瀏覽(29)
  • C++特殊類設(shè)計(單例模式)

    C++98 將拷貝構(gòu)造函數(shù)與賦值運算符重載只聲明不定義,并且將其訪問權(quán)限設(shè)置為私有即可。 原因: 設(shè)置成私有:如果只聲明沒有設(shè)置成private,用戶自己如果在類外定義了,就可以不能禁止拷貝了 只聲明不定義:不定義是因為該函數(shù)根本不會調(diào)用,定義了其實也沒有什么意義

    2024年01月19日
    瀏覽(24)
  • 【C++】特殊類設(shè)計(單例模式)

    【C++】特殊類設(shè)計(單例模式)

    設(shè)計模式是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類的、代碼設(shè)計經(jīng)驗的總結(jié)。 使用設(shè)計模式的目的:為了代碼可重用性、讓代碼更容易被他人理解、保證代碼可靠性。 根本原因是為了代碼復(fù)用,增加可維護(hù)性。 設(shè)計模式的例子:迭代器模式 拷貝一共就只有兩個場景,一

    2023年04月22日
    瀏覽(23)
  • 【C++】特殊類設(shè)計+單例模式+類型轉(zhuǎn)換

    【C++】特殊類設(shè)計+單例模式+類型轉(zhuǎn)換

    需要云服務(wù)器等云產(chǎn)品來學(xué)習(xí)Linux的同學(xué)可以移步/--騰訊云--/--阿里云--/--華為云--/官網(wǎng),輕量型云服務(wù)器低至112元/年,新用戶首次下單享超低折扣。 ? 目錄 一、設(shè)計一個類,不能被拷貝 1、C++98 2、C++11 二、設(shè)計一個類,只能在堆上創(chuàng)建對象 1、將構(gòu)造設(shè)為私有 2、將析構(gòu)設(shè)為

    2024年02月06日
    瀏覽(23)
  • 【C++高階(八)】單例模式&特殊類的設(shè)計

    【C++高階(八)】單例模式&特殊類的設(shè)計

    ??博主CSDN主頁:杭電碼農(nóng)-NEO?? ? ?專欄分類:C++從入門到精通? ? ??代碼倉庫:NEO的學(xué)習(xí)日記?? ? ??關(guān)注我??帶你學(xué)習(xí)C++ ? ???? 在實際場景中,總會遇見一些特殊情況, 比如設(shè)計一個類,只能在堆上開辟空間, 亦或者是設(shè)計一個類只能實例化一個對象 在實際需求的場景

    2024年02月04日
    瀏覽(20)
  • C++面試:單例模式、工廠模式等簡單的設(shè)計模式 & 創(chuàng)建型、結(jié)構(gòu)型、行為型設(shè)計模式的應(yīng)用技巧

    ????????理解和能夠?qū)崿F(xiàn)基本的設(shè)計模式是非常重要的。這里,我們將探討兩種常見的設(shè)計模式:單例模式和工廠模式,并提供一些面試準(zhǔn)備的建議。 目錄 單例模式 (Singleton Pattern) 工廠模式 (Factory Pattern) 面試準(zhǔn)備? 1. 理解設(shè)計模式的基本概念 2. 掌握實現(xiàn)細(xì)節(jié) 3. 討論優(yōu)缺

    2024年02月01日
    瀏覽(21)
  • C++中特殊類的設(shè)計與單例模式的簡易實現(xiàn)

    C++中特殊類的設(shè)計與單例模式的簡易實現(xiàn)

    對于這種特殊類的設(shè)計我們一般都是優(yōu)先考慮私有構(gòu)造函數(shù)。 然后對于一些特殊要求就直接通過靜態(tài)成員函數(shù)的實現(xiàn)來完成。 ?這里選擇禁掉拷貝構(gòu)造函數(shù)和拷貝函數(shù)是為了防止將已創(chuàng)建的對象去拷貝構(gòu)造新的對象。 ?這里如果沒有禁掉operator new和operator delete的話就會導(dǎo)致以

    2024年01月18日
    瀏覽(28)
  • 從C語言到C++_37(特殊類設(shè)計和C++類型轉(zhuǎn)換)單例模式

    從C語言到C++_37(特殊類設(shè)計和C++類型轉(zhuǎn)換)單例模式

    目錄 1. 特殊類設(shè)計 1.1 不能被拷貝的類 1.2 只能在堆上創(chuàng)建的類 1.3 只能在棧上創(chuàng)建的類 1.4 不能被繼承的類 1.5 只能創(chuàng)建一個對象的類(單例模式)(重點) 1.5.1 餓漢模式 1.5.2?懶漢模式 2.?類型轉(zhuǎn)換 2.1 static_cast 2.2 reinterpret_cast 2.3 const_cast 2.4 dynamic_cast 3. RTTI(了解)和類型轉(zhuǎn)換常見面

    2024年02月10日
    瀏覽(26)
  • 懶漢單例設(shè)計模式與餓漢單例設(shè)計模式

    單例模式即一個類確保只有一個對象,主要用于避免浪費內(nèi)存 1 .餓漢單例設(shè)計模式 :拿到對象時,對象就早已經(jīng)創(chuàng)建好了 寫法: 把類的構(gòu)造器私有 在類中自己創(chuàng)建一個對象,并賦值到一個變量 定義一個靜態(tài)方法,返回自己創(chuàng)建的這個對象 2. 懶漢單例設(shè)計模式 :第一次拿到對象時

    2024年02月21日
    瀏覽(31)
  • 【設(shè)計模式】單例設(shè)計模式

    目錄 1、前言 2、基本語法 2.1、懶漢式單例 2.2、餓漢式單例 2.3、雙重檢驗鎖單例模式 2.4、靜態(tài)內(nèi)部類單例模式 2.5、枚舉單例模式 2.6、ThreadLocal單例模式 2.7、注冊單例模式 3、使用場景 4、使用示例 5、常見問題 5、總結(jié) 單例模式是一種設(shè)計模式,它確保一個類只能創(chuàng)建一個實

    2024年02月09日
    瀏覽(29)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包