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

C++智能指針的補(bǔ)充和特殊類的設(shè)計(jì)示例詳解

 更新時(shí)間:2025年11月07日 09:52:42   作者:花一流  
智能指針不僅能夠有效避免內(nèi)存泄漏,還能簡(jiǎn)化代碼邏輯,提升程序的健壯性和可維護(hù)性,這篇文章主要介紹了C++智能指針的補(bǔ)充和特殊類設(shè)計(jì)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

定制刪除器:

補(bǔ)充上節(jié)關(guān)于未講到的智能指針的一些實(shí)踐中經(jīng)常出現(xiàn)的問題

int main()
{
	txf::shared_ptr<A> sp1(new A(1));
	return 0;
}

這樣寫是沒問題的,他會(huì)構(gòu)造和析構(gòu),但如果這樣寫呢?

int main()
{
	txf::shared_ptr<A> sp1(new A(1));
    txf::shared_ptr<A> sp2(new A[10]);
	return 0;
}
  • DeleteArray<A>() : 匿名對(duì)象

由于這里的虛構(gòu)函數(shù)是寫死的 ,這就會(huì)導(dǎo)致,這里有九個(gè)對(duì)象,還沒有釋放

甚至如果說這里是malloc 

int main()
{
	txf::shared_ptr<A> sp1(new A(1));

	txf::shared_ptr<A> sp2(new A[10]);// DeleteArray<A>()匿名對(duì)象
	
	txf::shared_ptr<A> sp3((A*)malloc(sizeof(A)));
	return 0;
}
  • 我們之前就說過malloc匹配free, new要匹配delete,這就明顯是不匹配的,不匹配就會(huì)出問題
  • 那庫里面是怎么解決這個(gè)問題的呢?->
  • 這個(gè)問題也叫做定制刪除器 (依靠仿函數(shù)來解決)
		template<class D>
		shared_ptr(T* ptr,D del)
			:_ptr(ptr) 
            ,_pcount(new int(1))
		{
		}
  • 這是庫里解決的方法,在構(gòu)造函數(shù)加了一個(gè),模板參數(shù)D,他要傳D類型的仿函數(shù)給他,那我們肯定也要接收這個(gè)仿函數(shù),用誰接收呢?那就想到在類里面要定義一個(gè)仿函數(shù)來接收
	template<class D>
	shared_ptr(T* ptr,D del)
		:_ptr(ptr) ,_pcount(new int(1)),_del(del)
	{
	}
private:
	T* _ptr;
	int* _pcount;
	
	D _del;
  • 直接增加一個(gè)D類型的仿函數(shù),這個(gè)D類型能在這里用嗎?
  • D是構(gòu)造函數(shù)的模板參數(shù),不是類模板的模板參數(shù),不能這么寫;我們要在析構(gòu)函數(shù)用到del,是del在構(gòu)造函數(shù)怎么辦?我們可以用它來創(chuàng)建一個(gè)成員變量,但是他類型是什么?因?yàn)镈這個(gè)是專門在構(gòu)造函數(shù),才能用的,不是構(gòu)造函數(shù),不能寫D類型,不能明確他的類型,那我們?cè)鯓觿?chuàng)建一個(gè)成員中間?如果說del成員專門寫成仿函數(shù)類型,那如果傳的是函數(shù)指針或者lambda怎么辦呢?這里我們就要用前面講的包裝器,包裝器可以接收他們仨個(gè)類型中的任意一個(gè)類型
	private:
		T* _ptr;
		int* _pcount;
		//D _del //D是構(gòu)造函數(shù)的模板參數(shù),不是類模板的模板參數(shù),不能這么寫;
		//我們要在析構(gòu)函數(shù)用到del,但是del在構(gòu)造函數(shù)怎么辦?
		// 我們可以用它來創(chuàng)建一個(gè)成員變量,但是他類型是什么?
		// 因?yàn)镈這個(gè)是專門在構(gòu)造函數(shù),才能用的,不是構(gòu)造函數(shù),不能寫D類型,
		// 不能明確他的類型,那我們?cè)鯓觿?chuàng)建一個(gè)成員中間?
		// 如果說del成員專門寫成仿函數(shù)類型,那如果傳的是函數(shù)指針或者lambda怎么辦呢?
		// 這里我們就要用前面講的包裝器,包裝器可以接收他們仨個(gè)類型中的任意一個(gè)類型
		 
		function<void(T*)> _del
		 //void : 被調(diào)用函數(shù)的返回類型
		 // T* :被調(diào)用函數(shù)的形參
		//int _pcount 如果是這樣,每個(gè)對(duì)象的_pcount都是獨(dú)立的
		
  • void : 被調(diào)用函數(shù)的返回類型
  • T* :被調(diào)用函數(shù)的形參

我們寫一個(gè)專門處理多個(gè)對(duì)象的仿函數(shù)傳給他,這樣就能在析構(gòu)函數(shù)中用這個(gè)仿函數(shù),

template<class T>
struct DeleteArray
{
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};
int main()
{
	txf::shared_ptr<A> sp1(new A(1));
	//由于這里的虛構(gòu)函數(shù)是寫死的 如果這樣寫呢?
	txf::shared_ptr<A> sp2(new A[10], DeleteArray<A>());// DeleteArray<A>()匿名對(duì)象
	//那這里有九個(gè)對(duì)象,還沒有釋放
	//甚至如果說這里是malloc 
	txf::shared_ptr<A> sp3((A*)malloc(sizeof(A)), [](A* ptr) {free(ptr); });
	//我們之前就說過malloc匹配free, new要匹配delete,這就明顯是不匹配的,不匹配就會(huì)出問題
	//那庫里面是怎么解決這個(gè)問題的呢?->定制刪除器(仿函數(shù))
	return 0;
}
	~shared_ptr()
	{
		if (--(*_pcount) == 0)
		{
			cout << "delete:" << _ptr << endl;
			_del(_ptr);
			delete _pcount;
		}
	}

這樣是不是看起來沒問題了?其實(shí)不是的,我們看似是解決了多個(gè)對(duì)象銷毀的問題,但是我們好像又不能處理單個(gè)對(duì)象銷毀的問題,單個(gè)對(duì)象銷毀需要的是delete而不是delete[] , 所以我們要給包裝器加個(gè)缺省值,

private:
	T* _ptr;
	int* _pcount;

	function<void(T*)> _del = [](T* ptr) {delete ptr; };//要先給一個(gè)lambda,要不然這個(gè)就專門設(shè)計(jì)成了處理多個(gè)對(duì)象的了,反而處理當(dāng)個(gè)對(duì)象就不行了,所以還要再寫一個(gè)拷貝函數(shù)
	 //void : 被調(diào)用函數(shù)的返回類型
	 // T* :被調(diào)用函數(shù)的形參
	
};
  • 要先給一個(gè)lambda,要不然這個(gè)就專門設(shè)計(jì)成了處理多個(gè)對(duì)象的了,反而處理當(dāng)個(gè)對(duì)象就不行了,所以還要再寫一個(gè)構(gòu)造函數(shù),

一個(gè)構(gòu)造是構(gòu)造單個(gè)對(duì)象的一個(gè)構(gòu)造函數(shù)是處理多個(gè)對(duì)象的 ,要處理多個(gè)對(duì)象,我們就要傳反函數(shù)給他,這樣兩個(gè)構(gòu)造函數(shù)就能構(gòu)成重載

	shared_ptr(T* ptr)
		:_ptr(ptr), _pcount(new int(1))
	{
	}

	template<class D>
	shared_ptr(T* ptr,D del)
		:_ptr(ptr) ,_pcount(new int(1)),_del(del)
	{
	}

以上就是關(guān)于定制刪除器的問題

一、請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,不能被拷貝

拷貝只會(huì)放生在兩個(gè)場(chǎng)景中:拷貝構(gòu)造函數(shù)以及賦值運(yùn)算符重載,因此想要讓一個(gè)類禁止拷貝,只需讓該類不能調(diào)用拷貝構(gòu)造函數(shù)以及賦值運(yùn)算符重載即可

  • C++98的做法
class A
{
    // ...
    
private:
    A(const A&);
    A& operator=(const A&);
    //...};

將拷貝構(gòu)造函數(shù)與賦值運(yùn)算符重載只聲明不定義,并且將其訪問權(quán)限設(shè)置為私有即可

  1.  設(shè)置成私有:如果只聲明沒有設(shè)置成private,用戶自己如果在類外定義了,就可以不
    能禁止拷貝了
  2. 只聲明不定義:不定義是因?yàn)樵摵瘮?shù)根本不會(huì)調(diào)用,定義了其實(shí)也沒有什么意義,不寫反而還簡(jiǎn)單,而且如果定義了就不會(huì)防止成員函數(shù)內(nèi)部拷貝了
  • C++11的做法
class A
{
    // ...
    
    A(const A&)=delete;
    A& operator=(const A&)=delete;
    //...};
  1. C++11擴(kuò)展delete的用法,delete除了釋放new申請(qǐng)的資源外,如果在默認(rèn)成員函數(shù)后跟上=delete,表示讓編譯器刪除掉該默認(rèn)成員函數(shù)

二、 請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,只能在堆上創(chuàng)建對(duì)象

設(shè)計(jì)一個(gè)類,只能在堆上創(chuàng)建對(duì)象 ->什么意思  :  只能顯式申請(qǐng)堆來創(chuàng)建對(duì)象,禁止掉一切除該方法外創(chuàng)建對(duì)象的行為如 :int a;

int main()
{
	HeapOnly hp1;//創(chuàng)建在棧上
	static HeapOnly hp2;//創(chuàng)建在靜態(tài)區(qū)上
	HeapOnly* hp3 = new HeapOnly;//創(chuàng)建在堆上

	return 0;
}

看到以上的區(qū)別后,那該怎么做呢?
由于在棧上和靜態(tài)區(qū)上創(chuàng)建的對(duì)象,他們都是能夠自動(dòng)調(diào)用析構(gòu)函數(shù)去釋放空間的,
 而創(chuàng)建在堆上的對(duì)象的需要手動(dòng)的去調(diào)用析構(gòu)函數(shù)去釋放空間,
 所以我們把能自動(dòng)釋放的析構(gòu)函數(shù)給禁掉,這樣系統(tǒng)就不允許你在棧上和靜態(tài)區(qū)上創(chuàng)建對(duì)象,因?yàn)闆]有析構(gòu)函數(shù)
這樣只能在堆上創(chuàng)建對(duì)象,但是在堆上創(chuàng)建對(duì)象,你也需要去釋放對(duì)象
而我們把析構(gòu)函數(shù)給私有化之后,我們可以再創(chuàng)建一個(gè)公共函數(shù),調(diào)用析構(gòu)函數(shù)
私有化限定的是類外面,而不會(huì)限定類里面

class HeapOnly
{
public:
	void Destroy()
	{
		cout << " deletec  : " << this << endl;
		delete this;
	}	
private:
	~HeapOnly()
	{

	}
};

那還有沒有其他方法呢?有的
剛才是把析構(gòu)函數(shù)給禁掉,我們還可以把構(gòu)造函數(shù)給私有化,
我們?cè)谀抢锩姘褬?gòu)造函數(shù)給私有化,但是,
你可以創(chuàng)建一個(gè)函數(shù)來創(chuàng)建對(duì)象,當(dāng)然,這是針對(duì)于堆上創(chuàng)建對(duì)象
這樣你就不能調(diào)用構(gòu)造函數(shù),
你就不能在棧上或者在靜態(tài)區(qū)上創(chuàng)建對(duì)象,
只能手動(dòng)的去調(diào)用函數(shù)創(chuàng)建對(duì)象,
函數(shù)里面寫成在堆里面創(chuàng)建對(duì)象,
所以這樣寫就只能在堆上創(chuàng)建對(duì)象

class HeapOnly
{
public:
	void Destroy()
	{
		cout << " deletec  : " << this << endl;
		delete this;
	}
	HeapOnly* CreateObj()
    {
	}
	
private:
	~HeapOnly()
	{

	}
	HeapOnly()
	{

	}
};
  • static讓  CreateObj()  脫離對(duì)象,變成“類名::函數(shù)”這種普通全局入口 , 讓它變成靜態(tài)區(qū)的一個(gè)函數(shù),變成一個(gè)用類名調(diào)用函數(shù)的形式,聲明類就可以調(diào)用,這樣不用非得要一個(gè)對(duì)象才能調(diào)用這個(gè)函數(shù)
  • 但是此時(shí)面臨個(gè)問題他不像是析構(gòu)函數(shù),使用已經(jīng)創(chuàng)建好的對(duì)象去調(diào)用一個(gè)函數(shù),他這里是需要?jiǎng)?chuàng)建一個(gè)對(duì)象去給一個(gè)指針,但是誰來調(diào)用這個(gè)函數(shù)呢?我們并沒有對(duì)象,我們還要靠這個(gè)函數(shù)來創(chuàng)造對(duì)象,但是又需要一個(gè)對(duì)象來調(diào)用這個(gè)函數(shù)這就有點(diǎn)像是先有雞還是先有蛋的問題

static讓  CreateObj()  脫離對(duì)象,變成“類名::函數(shù)”這種普通全局入口

讓它變成靜態(tài)區(qū)的一個(gè)函數(shù),變成一個(gè)用類名調(diào)用函數(shù)的形式,聲明類就可以調(diào)用,這樣不用非得要一個(gè)對(duì)象才能調(diào)用這個(gè)函數(shù)

static HeapOnly* CreateObj()//static讓  CreateObj()  脫離對(duì)象,變成“類名::函數(shù)”這種普通全局入口
{                           //讓它變成靜態(tài)區(qū)的一個(gè)函數(shù),變成一個(gè)用類名調(diào)用函數(shù)的形式,聲明類就可以調(diào)用,
							// 這樣不用非得要一個(gè)對(duì)象才能調(diào)用這個(gè)函數(shù)

	return new HeapOnly;//但是此時(shí)面臨個(gè)問題
	//他不像是析構(gòu)函數(shù),使用已經(jīng)創(chuàng)建好的對(duì)象去調(diào)用一個(gè)函數(shù),
	// 他這里是需要?jiǎng)?chuàng)建一個(gè)對(duì)象去給一個(gè)指針,但是誰來調(diào)用這個(gè)函數(shù)呢?
	// 我們并沒有對(duì)象,我們還要靠這個(gè)函數(shù)來創(chuàng)造對(duì)象,
	// 但是又需要一個(gè)對(duì)象來調(diào)用這個(gè)函數(shù)
	//這就有點(diǎn)像是先有雞還是先有蛋的問題
}

此時(shí)我們并沒有??掉他的拷貝構(gòu)造函數(shù),他依舊能夠拷貝構(gòu)造一個(gè)對(duì)象,這個(gè)創(chuàng)建的對(duì)象在棧上

HeapOnly hp4(*hp3);

所以還要把拷貝構(gòu)造給封一下

private:
	~HeapOnly()
	{

	}
	HeapOnly()
	{

	}
	HeapOnly(const HeapOnly& hp) = delete;
	HeapOnly&  operator=(const HeapOnly& hp) = delete;

三、請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,只能在棧上創(chuàng)建對(duì)象

請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,只能在棧上創(chuàng)建對(duì)象

什么叫“設(shè)計(jì)一個(gè)類只能在棧上創(chuàng)建對(duì)象”
允許  A a;  、  A a(args); 
 絕對(duì)禁止  new A  、  new A[10]
 把  operator new  全家桶全部封殺(含全局、數(shù)組、 placement 等)
 把析構(gòu)函數(shù)留在公有,否則棧對(duì)象離開作用域無法自動(dòng)析構(gòu)
 (可選)把構(gòu)造函數(shù)公有,否則連棧實(shí)例也建不了。

 一句話總結(jié) “只能在棧上創(chuàng)建”=把通往堆的所有后門(operator new)全部焊死

class StackOnly
{
public:
	static StackOnly CreateObj()
	{
		StackOnly st;
		return st;
	}

private:
	StackOnly()
	{ }
};

int main()
{
	StackOnly sp1= StackOnly::CreateObj();
	return 0;
}
  • ??掉構(gòu)造函數(shù),只給一個(gè)CreateObj函數(shù),讓外界調(diào)用它來初始化,
    在CreateObj函數(shù)里面限制,只從棧上面創(chuàng)造對(duì)象,這樣,你怎么樣都不可能從堆上創(chuàng)建對(duì)象,
    在CreateObj函數(shù)內(nèi)創(chuàng)建一個(gè)對(duì)象返回它

但是該方法還是存在問題

	StackOnly* sp2 = new StackOnly(sp1); 
  • 這樣拷貝對(duì)象建立出來的對(duì)象還是在棧上面

new 的時(shí)候可以調(diào)構(gòu)造,還可以調(diào)拷貝構(gòu)造
 new  表達(dá)式” = operator new(拿內(nèi)存) + 構(gòu)造函數(shù)(初始化),operator new相當(dāng)于全家桶
我們可以重載一個(gè)類的專屬的operator new,這樣他就不會(huì)調(diào)用全局,而會(huì)調(diào)用我們重載的operator new ,讓void* operator new(size_t size) = delete; 把通往堆的所有后門(operator new)全部焊死

class StackOnly
{
public:
	static StackOnly CreateObj()
	{
		StackOnly st;
		return st;
	}

private:
	StackOnly()
	{ }

	void* operator new(size_t size) = delete;//把通往堆的所有后門(operator new)全部焊死
};

int main()
{
	StackOnly sp1= StackOnly::CreateObj();

	//StackOnly* sp2 = new StackOnly(sp1); //這樣就不能拷貝了
	
	return 0;
}

四、設(shè)計(jì)一個(gè)類不能被繼承

  • C++98的方式
class NonInherit
{
public:
 static NonInherit GetInstance()
 {
 return NonInherit();
 }
private:
 NonInherit()
 {}
};
  1. C++98中構(gòu)造函數(shù)私有化,派生類中調(diào)不到基類的構(gòu)造函數(shù)。則無法繼承
  • C++11的方法
class A  final
{
    // ....
};
  1. final關(guān)鍵字,final修飾類,表示該類不能被繼承

五、 請(qǐng)?jiān)O(shè)計(jì)一個(gè)類,只能創(chuàng)建一個(gè)對(duì)象(單例模式)

5.1餓漢模式

單例模式:一個(gè)類只能創(chuàng)建一個(gè)對(duì)象,即單例模式(用這個(gè)類定義出來的對(duì)象,不管名字是否相同,都是同一個(gè)對(duì)象) ,該模式可以保證系統(tǒng)中該類只有一個(gè)實(shí)例,并提供一個(gè)
訪問它的全局訪問點(diǎn),該實(shí)例被所有程序模塊共享。比如在某個(gè)服務(wù)器程序中,該服務(wù)器的配置
信息存放在一個(gè)文件中,這些配置數(shù)據(jù)由一個(gè)單例對(duì)象統(tǒng)一讀取,然后服務(wù)進(jìn)程中的其他對(duì)象再通過這個(gè)單例對(duì)象獲取這些配置信息,這種方式簡(jiǎn)化了在復(fù)雜環(huán)境下的配置管理

class singleton
{
public:
	//步驟二
	//提供獲取單例對(duì)象的接口函數(shù)
	static singleton&  GetInstance()
	{
		return _sinst;
	}

	
	// singleton sinst;

	//一般單例不用釋放


	void Add(const pair<string, string>& kv)
	{
		_dict[kv.first] = kv.second;
	}

private:
	//單例模式步驟一
	//構(gòu)造函數(shù)私有
	map<string, string> _dict;
	singleton()
	{

	}

	//步驟三
	//防拷貝
	singleton (const singleton& s) = delete;
	singleton& operator=(const singleton& s) = delete;

	static singleton _sinst;//聲明一個(gè)成員變量
};

//類的靜態(tài)成員變量需要在類外初始化
 singleton singleton:: _sinst;//實(shí)例化變量
 //雖然存儲(chǔ)在靜態(tài)區(qū),但由于在singleton類中聲明了,所以它依然能享用到構(gòu)造函數(shù),而且在靜態(tài)區(qū),所以只用聲明在哪個(gè)類域


int main()
{
	//singleton s1;//不能隨意創(chuàng)建對(duì)象
	//singleton s2;
	//if (&s1 == &s2)
	//{
	//	cout << "a" << endl;
	//}
	//else
	//{
	//	cout << " b";
	//}

	//cout << &singleton::GetInstance() << endl;
	//cout << &singleton::GetInstance() << endl;
	//cout << &singleton::GetInstance() << endl;

	//還要把拷貝給禁掉,要不然還能拷貝
	//singleton copy(singleton::GetInstance());
  return 0;
}
  • 單例模式步驟一 : 構(gòu)造函數(shù)私有
class singleton
{
public:
  
private:
	//單例模式步驟一
	//構(gòu)造函數(shù)私有
	singleton()
	{

	}
}:
  • 步驟二 : 提供獲取單例對(duì)象的接口函數(shù)
class singleton
{
public:
      	//步驟二
	//提供獲取單例對(duì)象的接口函數(shù)
	static singleton&  GetInstance()
	{
		return _sinst;
	}
private:
	//單例模式步驟一
	//構(gòu)造函數(shù)私有
	singleton()
	{

	}
}:
  1. 首先,我們把構(gòu)造函數(shù)私有化之后,我們要?jiǎng)?chuàng)建一個(gè)靜態(tài)成員函數(shù)來獲取單例對(duì)象,如果不是靜態(tài)的,那么要想調(diào)用這個(gè)函數(shù),就必須要一個(gè)對(duì)象,而我們就是要構(gòu)造出一個(gè)對(duì)象,所以這就死循環(huán)了,但是如果把它設(shè)置為靜態(tài)的,它就存儲(chǔ)在靜態(tài)區(qū),這樣就可以用類::的方式來調(diào)用獲取單例對(duì)象的函數(shù),而不用非得要?jiǎng)?chuàng)建一個(gè)對(duì)象,才能調(diào)用這個(gè)函數(shù),
  2. 其次,我們正常來說一個(gè)類是不可能只實(shí)例化出一份對(duì)象的,所以我們要想到全局對(duì)象或者靜態(tài)對(duì)象在作用域內(nèi)是只有一份的,

  1. 所以我們要把對(duì)象設(shè)置為全局或者是靜態(tài)的,由于構(gòu)造函數(shù)是私有的,在類外面是無法創(chuàng)建對(duì)象的,所以我們要想辦法讓創(chuàng)建對(duì)象可以放到單例類的內(nèi)部,用于調(diào)用構(gòu)造函數(shù),所以我們要用靜態(tài)成員變量,在單例類的內(nèi)部,聲明一個(gè)靜態(tài)成員對(duì)象,他這個(gè)對(duì)象是純屬在靜態(tài)區(qū)的,是不屬于這個(gè)類的,所以在這里不會(huì)套娃式的不斷在內(nèi)部創(chuàng)造,而是只會(huì)實(shí)例化一次,并且存儲(chǔ)在靜態(tài)區(qū),這樣這個(gè)靜態(tài)成員對(duì)象就可以訪問構(gòu)造函數(shù),但是類的靜態(tài)成員變量是需要在類外面初始化的,所以我們就在單例內(nèi)的外部,初始化定義這個(gè)靜態(tài)的單一類對(duì)象即可
  • 步驟三 : 防拷貝

還要把拷貝給禁掉,要不然還能拷貝

  singleton copy(singleton::GetInstance());

完整代碼:

class singleton
{
public:
	//步驟二
	//提供獲取單例對(duì)象的接口函數(shù)
	static singleton&  GetInstance()
	{
		return _sinst;
	}

	
	// singleton sinst;

	//一般單例不用釋放


	void Add(const pair<string, string>& kv)
	{
		_dict[kv.first] = kv.second;
	}

private:
	//單例模式步驟一
	//構(gòu)造函數(shù)私有
	map<string, string> _dict;
	singleton()
	{

	}

	//步驟三
	//防拷貝
	singleton (const singleton& s) = delete;
	singleton& operator=(const singleton& s) = delete;

	static singleton _sinst;//聲明一個(gè)成員變量
};

//類的靜態(tài)成員變量需要在類外初始化
 singleton singleton:: _sinst;//實(shí)例化變量
 //雖然存儲(chǔ)在靜態(tài)區(qū),但由于在singleton類中聲明了,所以它依然能享用到構(gòu)造函數(shù),而且在靜態(tài)區(qū),所以只用聲明在哪個(gè)類域

以上這種模式也叫做餓漢模式, 

就是說不管你將來用不用,程序啟動(dòng)時(shí)就創(chuàng)建一個(gè)唯一的實(shí)例對(duì)象,在一開始(main函數(shù))之前就創(chuàng)建單例對(duì)象

不過他也有缺陷,以下是餓漢模式的缺陷 :

  1. 如果單例對(duì)象要初始化的內(nèi)容很多,那么就會(huì)影響進(jìn)程的啟動(dòng)速度
  2. 如果兩個(gè)單例類,互相有依賴關(guān)系,例如:有兩個(gè)單例類A,B。要求A先創(chuàng)建,B再創(chuàng)建,B的初始化依賴于A。倘若單例類A,B不在同一個(gè)文件,那么我們無法保證編譯器會(huì)去先執(zhí)行哪一個(gè)文件,那么就無法保證A始終是先被創(chuàng)建的,那么B的初始化工作可能就無法運(yùn)行,這就很坑

下面介紹另一種模式,專門解決餓漢模式的缺陷 : 懶漢模式

5.2懶漢模式

懶漢模式:用來解決餓漢模式的問題 (_sinst 改成指針,這樣就不用先創(chuàng)建對(duì)象導(dǎo)致啟動(dòng)慢,等到要調(diào)用對(duì)象的時(shí)候,再創(chuàng)建對(duì)象

懶漢模式中的靜態(tài)成員變量,不是一個(gè)單例對(duì)象 ,而是一個(gè)單例對(duì)象的指針,我們可以將這個(gè)單例對(duì)象的指針初始化為nullptr,這樣也就不會(huì)調(diào)用構(gòu)造函數(shù)了,等到真正使用單例對(duì)象的時(shí)候,判斷單例對(duì)象的指針是否為空,如果單例對(duì)象的指針為空,那么就說明此時(shí)單例對(duì)象還未調(diào)用構(gòu)造函數(shù)創(chuàng)建,此時(shí)我們new一個(gè)單例對(duì)象給單例對(duì)象的指針即可,這樣就調(diào)用了單例類的構(gòu)造函數(shù)進(jìn)行的初始化單例對(duì)象,因?yàn)橐婚_始僅僅創(chuàng)建一個(gè)空指針沒有什么消耗,所以不會(huì)影響進(jìn)程的啟動(dòng)速度, 當(dāng)?shù)谝淮握嬲枰褂脝卫龑?duì)象的時(shí)候才會(huì)進(jìn)行new調(diào)用構(gòu)造函數(shù)實(shí)例化

namespace lazy
{
	class Singleton
	{
	public:
		static Singleton& GetInstace()
		{
			if (_sinst == nullptr)
			{
				_sinst = new Singleton();
			}

			return *_sinst;
		}

	private:
		Singleton()
		{}

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

		static Singleton* _sinst;
	};

	Singleton* Singleton::_sinst = nullptr;
}

總結(jié)

以上就是今天要講的內(nèi)容,本文僅僅簡(jiǎn)單介紹了幾個(gè)特殊類,還有相關(guān)的單例模式,說實(shí)話在寫的時(shí)候,小編并未完全弄清楚單例模式以及相關(guān)的優(yōu)化場(chǎng)景,所以就只是簡(jiǎn)單的介紹了一下,小編要下去再好好弄清楚,弄清楚后再來補(bǔ)充

到此這篇關(guān)于C++智能指針的補(bǔ)充和特殊類的設(shè)計(jì)的文章就介紹到這了,更多相關(guān)C++智能指針和特殊類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C/C++在VScode中的配置教程詳解

    C/C++在VScode中的配置教程詳解

    這篇文章主要介紹了C/C++在VScode中的配置教程詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 詳解C語言之文件操作(上)

    詳解C語言之文件操作(上)

    這篇文章主要介紹了關(guān)于C語言文件操作方法的相關(guān)資料,小編覺得這篇文章寫的還不錯(cuò),需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-11-11
  • C++學(xué)習(xí)筆記之pimpl用法詳解

    C++學(xué)習(xí)筆記之pimpl用法詳解

    在編寫穩(wěn)定代碼是,管理好代碼間的依賴性是不可缺少的一個(gè)環(huán)節(jié)。特別是庫文件的編寫中,減少代碼間的依賴性可以提供一個(gè)“干凈”的接口。下面這篇文章主要給大家介紹了關(guān)于C++中pimpl用法的相關(guān)資料,需要的朋友可以參考下。
    2017-08-08
  • C++中的單例模式介紹

    C++中的單例模式介紹

    單例模式也稱為單件模式、單子模式,可能是使用最廣泛的設(shè)計(jì)模式。其意圖是保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn),該實(shí)例被所有程序模塊共享
    2013-03-03
  • C++深入刨析類與對(duì)象的使用

    C++深入刨析類與對(duì)象的使用

    類和對(duì)象是兩種以計(jì)算機(jī)為載體的計(jì)算機(jī)語言的合稱。對(duì)象是對(duì)客觀事物的抽象,類是對(duì)對(duì)象的抽象。類是一種抽象的數(shù)據(jù)類型;變量就是可以變化的量,存儲(chǔ)在內(nèi)存中—個(gè)可以擁有在某個(gè)范圍內(nèi)的可變存儲(chǔ)區(qū)域
    2022-05-05
  • C++中輸出十六進(jìn)制形式的字符串

    C++中輸出十六進(jìn)制形式的字符串

    這篇文章主要給大家介紹了C++中輸出十六進(jìn)制形式的字符串,文中給出了詳細(xì)的介紹,有需要的朋友可以參考借鑒,下面來一起看看吧。
    2016-12-12
  • QT使用SQLite數(shù)據(jù)庫超詳細(xì)教程(增刪改查、對(duì)大量數(shù)據(jù)快速存儲(chǔ)和更新)

    QT使用SQLite數(shù)據(jù)庫超詳細(xì)教程(增刪改查、對(duì)大量數(shù)據(jù)快速存儲(chǔ)和更新)

    這篇文章主要給大家介紹了關(guān)于QT使用SQLite數(shù)據(jù)庫的相關(guān)資料,其中包括增刪改查以及對(duì)大量數(shù)據(jù)快速存儲(chǔ)和更新,SQLite是一種嵌入式關(guān)系型數(shù)據(jù)庫管理系統(tǒng),它是一個(gè)軟件庫,提供了一個(gè)自包含、無服務(wù)器、零配置的、事務(wù)性的SQL數(shù)據(jù)庫引擎,需要的朋友可以參考下
    2024-01-01
  • C語言實(shí)現(xiàn)學(xué)生宿舍信息管理系統(tǒng)

    C語言實(shí)現(xiàn)學(xué)生宿舍信息管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)學(xué)生宿舍信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java?C++?leetcode面試零矩陣

    Java?C++?leetcode面試零矩陣

    這篇文章主要為大家介紹了Java?C++題解leetcode面試零矩陣示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 區(qū)分C++中的&和&&

    區(qū)分C++中的&和&&

    這篇文章主要介紹了如何區(qū)分C++的&和&&,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2020-09-09

最新評(píng)論

东乡族自治县| 平阴县| 阿瓦提县| 平度市| 沙洋县| 盐池县| 庐江县| 理塘县| 桐梓县| 泸溪县| 永泰县| 香河县| 凯里市| 临湘市| 兰州市| 讷河市| 陆丰市| 达孜县| 金湖县| 德州市| 德昌县| 衡阳县| 同江市| 肥城市| 察雅县| 古交市| 麻栗坡县| 平遥县| 霍林郭勒市| 大田县| 茌平县| 肥西县| 西林县| 汉川市| 临江市| 同仁县| 布尔津县| 综艺| 鹿邑县| 隆回县| 开平市|