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

深入解析C++中的智能指針

 更新時(shí)間:2025年10月19日 11:43:55   作者:夜晚中的人海  
本文介紹了C++中RAII機(jī)制和智能指針的概念、使用及實(shí)現(xiàn)原理,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧

一、RAII和智能指針

RAII是Resource Acquisition Is Initialization的縮寫,它的意思是獲取資源立即初始化。本質(zhì)是?種利用對(duì)象生命周期來(lái)管理獲取到的動(dòng)態(tài)資源,避免資源泄漏

智能指針類除了滿足RAII的設(shè)計(jì)思路,還要方便對(duì)資源進(jìn)行訪問,所以智能指針類還會(huì)想迭代器類?樣,重載 operator*/operator->/operator[]等運(yùn)算符,

例:

template<class T>
class smart_ptr
{
public:
	smart_ptr(T* ptr)
		:_ptr(ptr)
	{}
	~smart_ptr()
	{
		cout << "delete[]" << _ptr << endl;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	T& operator[](size_t i)
	{
		return _ptr[i];
	}
private:
	T* _ptr;
};

二、C++標(biāo)準(zhǔn)庫(kù)智能指針的使用

C++標(biāo)準(zhǔn)庫(kù)中的智能指針都在< memory >這個(gè)頭文件下面,因此在使用前需要包含這一頭文件。除了weak_ptr以外,其它都符合RAII和像指針?樣訪問的行為,原因主要是解決智能指針拷貝時(shí)的思路不同

C++標(biāo)準(zhǔn)庫(kù)主要提供了四種智能指針:
auto_ptr: 它是在C++98中設(shè)計(jì)出來(lái)的智能指針,其特點(diǎn)是拷貝時(shí)把被拷貝對(duì)象的資源管理權(quán)轉(zhuǎn)移給拷貝對(duì)象,這個(gè)設(shè)計(jì)是非常糟糕的,因?yàn)樗鼤?huì)讓被拷貝的對(duì)象懸空,當(dāng)我們對(duì)其進(jìn)行訪問時(shí)會(huì)發(fā)生報(bào)錯(cuò)。因此在日常工作中不建議使用這一指針

以下這三種指針都是在C++11中設(shè)計(jì)出來(lái)的
unique_ptr:它的意思是唯一指針,其特點(diǎn)是不支持拷貝只支持移動(dòng),因此在不需要拷貝的場(chǎng)景下就可以使用它

shared_ptr: 它的意思是共享指針,其特點(diǎn)是支持拷貝也支持移動(dòng),因此在需要拷貝的場(chǎng)景下就可以使用它

weak_ptr:它的意思的弱指針,其完全不同于上面的智能指針,因?yàn)樗?strong>不支持RAII,也就意味著不能用它直接管理資源。其作用是用來(lái)解決循環(huán)引用的問題

例:

struct Date
{
	int _year;
	int _month;
	int _day;
	Date(int year = 1,int month = 1,int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	~Date()
	{
		cout << "~Date()" << endl;
	}
};
int main()
{
	auto_ptr<Date> ap1(new Date);
	//ap1的管理權(quán)轉(zhuǎn)移給ap2
	auto_ptr<Date> ap2(ap1);
	//報(bào)錯(cuò):對(duì)空指針進(jìn)行訪問
	ap1->_year++;
	unique_ptr<Date> up1(new Date);
	//報(bào)錯(cuò):不支持拷貝
	unique_ptr<Date> up2(up1);
	//支持移動(dòng),移動(dòng)后up1也為空,不能對(duì)其進(jìn)行訪問
	unique_ptr<Date> up2(move(up1));
	shared_ptr<Date> sp1(new Date);
	//支持拷貝也支持移動(dòng)
	shared_ptr<Date> sp2(sp1);
	shared_ptr<Date> sp3(move(sp1));
	return 0;
}

刪除器

智能指針析構(gòu)時(shí)默認(rèn)是進(jìn)行delete釋放資源,這也就意味著如果不是new出來(lái)的資源交給智能指針管理,析構(gòu)時(shí)就會(huì)崩潰。因此智能指針支持在構(gòu)造時(shí)給?個(gè)刪除器,而刪除器本質(zhì)就是?個(gè)可調(diào)用對(duì)象,這個(gè)可調(diào)用對(duì)象中實(shí)現(xiàn)你想要的釋放資源的方式。即當(dāng)我們?cè)跇?gòu)造智能指針時(shí),給了定制的刪除器,智能指針析構(gòu)時(shí)就會(huì)調(diào)用我們?cè)O(shè)計(jì)出的刪除器去釋放資源

struct Date
{
	int _year;
	int _month;
	int _day;
	Date(int year = 1,int month = 1,int day = 1)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
	~Date()
	{
		cout << "~Date()" << endl;
	}
};
template<class T>
class DeleteArray
{
public:
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};
template<class T>
void DeleteArrayFunc(T* ptr)
{
	deletr[] ptr;
};
int main()
{
	//這樣去構(gòu)造程序會(huì)報(bào)錯(cuò)
	//unique_ptr<Date> up(new Date[10]);
	//shared_ptr<Date> sp(new Date[10]);
	//解決方案1:因?yàn)閚ew[]經(jīng)常使用,因此unique_ptr和shared_ptr 
    //實(shí)現(xiàn)了?個(gè)特化版本,這個(gè)特化版本在析構(gòu)時(shí)用的delete[] 
	unique_ptr<Date[]> up(new Date[10]);
	shared_ptr<Date[]> sp(new Date[10]);
	//解決方案2:使用仿函數(shù)對(duì)象做刪除器
	//這里需要注意:unique_ptr和shared_ptr在支持刪除器的方式是有所不同的
	//unique_ptr在類模板參數(shù)支持的,shared_ptr是構(gòu)造函數(shù)參數(shù)支持的 
	unique_ptr<Date, DeleteArray<Date>> up1(new Date[10]);
	shared_ptr<Date> sp1(new Date[10], DeleteArray<Date>());
	// 函數(shù)指針做刪除器  
	unique_ptr<Date, void(*)(Date*)> up3(new Date[5], DeleteArrayFunc<Date>);
	shared_ptr<Date> sp3(new Date[5], DeleteArrayFunc<Date>);
	// lambda表達(dá)式做刪除器 
	auto del = [](Date* ptr) {delete[] ptr; };
	unique_ptr<Date, decltype(del)> up4(new Date[10], del);
	shared_ptr<Date> sp4(new Date[10], del);
	return 0;
}

使用時(shí)需要注意以下幾點(diǎn):
1.shared_ptr 除了支持用指向資源的指針構(gòu)造,還支持 make_shared 用初始化資源對(duì)象的值直接構(gòu)造。

2.shared_ptr 和 unique_ptr 都支持了operator bool的類型轉(zhuǎn)換,如果智能指針對(duì)象是?個(gè)空對(duì)象沒有管理資源,則返回false,否則返回true,意味著我們可以直接把智能指針對(duì)象給if判斷是否為空。

3.shared_ptr 和 unique_ptr 在構(gòu)造函數(shù)中都得使用explicit來(lái)修飾,防止普通指針隱式類型轉(zhuǎn)換成智能指針對(duì)象。

例:

int main()
{
	shared_ptr<Date> sp1(new Date(2025, 10, 9));
	shared_ptr<Date> sp2 = make_shared<Date>(2025, 10, 9);
	if (sp1)
		cout << "sp1 is not nullptr" << endl;
	return 0;
}

三、智能指針的原理及其模擬實(shí)現(xiàn)

1.auto_ptr

template<class T>
class auto_ptr
{
public:
	auto_ptr(T* ptr)
		:_ptr(ptr)
	{}
	auto_ptr(auto_ptr<T>& sp)
		:_ptr(sp._ptr)
	{
		sp._ptr = nullptr;
	}
	auto_ptr<T>& operator=(auto_ptr<T>& ap)
	{
		if (this != &ap)
		{
			if (_ptr)
				delete _ptr;
			_ptr = ap._ptr;
			ap._ptr = nullptr;
		}
		return *this;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
private:
	T* _ptr;
};

2.unique_ptr

template<class T>
	class unique_ptr
	{
	public:
		//	加explicit是防止普通指針隱式類型
		// 	轉(zhuǎn)化為智能指針對(duì)象
		explicit unique_ptr(T* ptr)
			:_ptr(ptr)
		{}
		~unique_ptr()
		{
			if (_ptr)
			{
				cout << "delete:" << _ptr << endl;
				delete _ptr;
			}
		}
		T* operator->()
		{
			return _ptr;
		}
		T& operator*()
		{
			return *_ptr;
		}
		//不支持左值的拷貝構(gòu)造
		unique_ptr(const unique_ptr<T>& up) = delete;
		//不支持左值的賦值
		unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;
		//支持右值的拷貝構(gòu)造
		unique_ptr(unique_ptr<T>&& up)
			:_ptr(up._ptr)
		{
			up._ptr = nullptr;
		}
		//支持右值的賦值
		unique_ptr<T>& operator=(unique_ptr<T>&& up)
		{
			delete _ptr;
			_ptr = up._ptr;
			up._ptr = nullptr;
		}
	private:
		T* _ptr;
	};
}

3.重點(diǎn):shared_ptr

shared_ptr的拷貝底層是采用引用計(jì)數(shù)的方式來(lái)實(shí)現(xiàn)的,讓多個(gè)shared_ptr對(duì)象共用同一份資源

template<class T>
	class shared_ptr
	{
	public:
		explicit shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			, _pcount(new int(1))
		{}
		//拷貝
		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			,_pcount(sp._pcount)
		{
			++(*_pcount);
		}
		~shared_ptr()
		{
			if (--(*_pcount) == 0)
			{
				delete _ptr;
				delete _pcount;
			}
		}
		//賦值
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				if (--(*_pcount) == 0)
				{
					delete _pcount;
					delete _ptr;
				}
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}
			return *this;
		}
		T* operator->()
		{
			return _ptr;
		}
		T& operator*()
		{
			return *_ptr;
		}
	private:
		T* _ptr;
		int* _pcount;
	};

定制刪除器版本:

template<class T>
class shared_ptr
{
public:
	explicit shared_ptr(T* ptr = nullptr)
		:_ptr(ptr)
		,_pcount(new int(1))
	{}
	template<class D>
	shared_ptr(T* ptr, D del)
		:_ptr(ptr)
		,_del(del)
		,_pcount(new int(1))
	{}
	void release()
	{
		if (--(*_pcount) == 0)
		{
			_del(_ptr);
			delete _pcount;
			_ptr = nullptr;
			_pcount = nullptr;
		}
	}
	shared_ptr(const shared_ptr<T>& sp)
		:_ptr(sp._ptr)
		,_pcount(sp._pcount)
		,_del(sp._del)
	{
		++(*_pcount);
	}
	~shared_ptr()
	{
		release();
	}
	shared_ptr<T>& operator=(const shared_ptr<T>& sp)
	{
		if (_ptr != sp._ptr)
		{
			release();
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			++(*_pcount);
			_del = sp._del;
		}
		return *this;
	}
	int use_count() const
	{
		return *_pcount;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
private:
	T* _ptr;
	int* _pcount;
	function<void(T*)> _del = [](T* ptr) {delete ptr; };
};

??四、shared_ptr和weak_ptr之間的關(guān)系

1.shared_ptr循環(huán)引用的問題

shared_ptr在大多數(shù)情況下管理資源都非常合適,但在循環(huán)引用場(chǎng)景下會(huì)出現(xiàn)內(nèi)存泄漏的問題,因此我們要學(xué)會(huì)使用weak_ptr來(lái)解決這類問題

當(dāng)n1和n2進(jìn)行析構(gòu)時(shí),引用計(jì)數(shù)為1不為0,導(dǎo)致內(nèi)存泄漏

2.weak_ptr的介紹及其模擬實(shí)現(xiàn)

weak_ptr不支持RAII,也不支持訪問資源,它支持綁定到shared_ptr,綁定到shared_ptr時(shí),不增加shared_ptr的引用計(jì)數(shù),因此就可以解決循環(huán)引用的問題

• weak_ptr也沒有重載operator*和operator->等,因?yàn)樗粎⑴c資源管理,但如果它綁定的shared_ptr已經(jīng)釋放了資源,我們?cè)趯?duì)其進(jìn)行訪問,那是非常危險(xiǎn)的。因此它設(shè)計(jì)出expired幫助我們檢查指向的資源是否過期,使用use_count也可獲取shared_ptr中的引用計(jì)數(shù)

例:

五、C++11和boost智能指針中的關(guān)系

Boost庫(kù)是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的?些C++程序庫(kù)的總稱,C++11及之后的新語(yǔ)法和庫(kù)有很多都是從Boost中來(lái)的

C++98中產(chǎn)生了第?個(gè)智能指針auto_ptr

C++boost庫(kù)也給出了更實(shí)用的scoped_ptr/scoped_array和shared_ptr/shared_array和weak_ptr等

C++TR1,引入了shared_ptr等,不過注意的是TR1并不是標(biāo)準(zhǔn)版

C++11,引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr對(duì)應(yīng)boost的scoped_ptr。并且這些智能指針的實(shí)現(xiàn)原理是參考boost中的實(shí)現(xiàn)的

六、內(nèi)存泄漏

1.什么是內(nèi)存泄漏以及造成的危害

內(nèi)存泄漏指因?yàn)槭韬龌蝈e(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存,?般是忘記釋放或者發(fā)生異常釋放程序未能執(zhí)行導(dǎo)致的。

危害:普通程序在資源少的情況下運(yùn)行?會(huì)就結(jié)束了出現(xiàn)內(nèi)存泄漏問題也不是很大。但在長(zhǎng)期運(yùn)行的程序以及有大量資源的情況下出現(xiàn)內(nèi)存泄漏,影響是非常大的,如操作系統(tǒng)、后臺(tái)服務(wù)、長(zhǎng)時(shí)間運(yùn)行的客戶端等等,不斷出現(xiàn)內(nèi)存泄漏會(huì)導(dǎo)致可用內(nèi)存不斷變少,各種功能響應(yīng)越來(lái)越慢,最終卡死。

2.如何避免內(nèi)存泄漏

1.養(yǎng)成良好的編碼規(guī)范,申請(qǐng)的內(nèi)存空間記著匹配的去釋放

2.盡量使用智能指針來(lái)管理資源,如果在某些場(chǎng)景比較特殊的情況下,采用RAII思想自己造個(gè)輪子來(lái)管理

3.定期使用內(nèi)存泄露工具

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

相關(guān)文章

  • 鏈接庫(kù)動(dòng)態(tài)鏈接庫(kù)詳細(xì)介紹

    鏈接庫(kù)動(dòng)態(tài)鏈接庫(kù)詳細(xì)介紹

    靜態(tài)鏈接庫(kù).lib和動(dòng)態(tài)鏈接庫(kù).dll。其中動(dòng)態(tài)鏈接庫(kù)在被使用的時(shí)候,通常還提供一個(gè).lib,稱為引入庫(kù),它主要提供被Dll導(dǎo)出的函數(shù)和符號(hào)名稱,使得鏈接的時(shí)候能夠找到dll中對(duì)應(yīng)的函數(shù)映射
    2012-11-11
  • C語(yǔ)言中常見的幾種流程控制語(yǔ)句

    C語(yǔ)言中常見的幾種流程控制語(yǔ)句

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言中常見的幾種流程控制語(yǔ)句,分別包括goto語(yǔ)句、if語(yǔ)句、switch語(yǔ)句、while循環(huán)、do...while循環(huán)、for循環(huán)以及break和continue等,需要的朋友可以參考下
    2021-08-08
  • C++ 構(gòu)造函數(shù)和析構(gòu)函數(shù)示例詳解

    C++ 構(gòu)造函數(shù)和析構(gòu)函數(shù)示例詳解

    本文詳細(xì)介紹了C++中的構(gòu)造函數(shù)和析構(gòu)函數(shù),包括它們的特點(diǎn)、調(diào)用時(shí)機(jī)以及在資源管理中的重要性,同時(shí),通過與Python的對(duì)比,展示了如何在Python中模擬C++的構(gòu)造函數(shù)特性,并強(qiáng)調(diào)了兩種語(yǔ)言在內(nèi)存管理和資源管理機(jī)制上的差異,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • 使用Matlab制作簡(jiǎn)易版八分音符醬游戲

    使用Matlab制作簡(jiǎn)易版八分音符醬游戲

    八分音符醬作為一款聲音控制類游戲,當(dāng)時(shí)還是很受大家的喜愛的。本文將用Matlab制作一款簡(jiǎn)易版的八分音符醬游戲,感興趣的可以學(xué)習(xí)一下
    2022-02-02
  • C++Smart Pointer 智能指針詳解

    C++Smart Pointer 智能指針詳解

    這篇文章主要為大家詳細(xì)介紹了C++Smart Pointer 智能指針,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • C++?STL容器適配器使用指南

    C++?STL容器適配器使用指南

    C++?STL(標(biāo)準(zhǔn)模板庫(kù))是一套功能強(qiáng)大的?C++?模板類,提供了通用的模板類和函數(shù),這些模板類和函數(shù)可以實(shí)現(xiàn)多種流行和常用的算法和數(shù)據(jù)結(jié)構(gòu),如向量、鏈表、隊(duì)列、棧,今天我們來(lái)探究一下stl容器適配器的使用吧
    2021-11-11
  • 基于OpenCV讀取攝像頭實(shí)現(xiàn)單個(gè)人臉驗(yàn)證MFC程序

    基于OpenCV讀取攝像頭實(shí)現(xiàn)單個(gè)人臉驗(yàn)證MFC程序

    這篇文章主要為大家詳細(xì)介紹了基于OpenCV讀取攝像頭實(shí)現(xiàn)單個(gè)人臉驗(yàn)證MFC程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • C語(yǔ)言浮點(diǎn)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)方式詳解

    C語(yǔ)言浮點(diǎn)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)方式詳解

    任何數(shù)據(jù)在內(nèi)存中都是以二進(jìn)制的形式存儲(chǔ)的,例如一個(gè)short型數(shù)據(jù)1156,其二進(jìn)制表示形式為00000100 10000100,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言浮點(diǎn)型數(shù)據(jù)在內(nèi)存中的存儲(chǔ)方式,需要的朋友可以參考下
    2023-03-03
  • 詳解C++中inline關(guān)鍵字的作用

    詳解C++中inline關(guān)鍵字的作用

    這篇文章主要為大家介紹了C++中的inline關(guān)鍵字,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-12-12
  • 一文詳解C++中隱含的this指針

    一文詳解C++中隱含的this指針

    這篇文章主要帶大家詳細(xì)了解一下C++中隱含的this指針,文中通過代碼示例和圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-01-01

最新評(píng)論

灵台县| 桃江县| 富顺县| 榆中县| 墨玉县| 河津市| 湘潭市| 贵阳市| 盐池县| 彝良县| 道真| 信宜市| 康马县| 绥阳县| 安吉县| 浠水县| 颍上县| 油尖旺区| 黄山市| 澳门| 石泉县| 长宁区| 彝良县| 建瓯市| 津南区| 婺源县| 乐昌市| 盐源县| 四平市| 平和县| 金门县| 武安市| 特克斯县| 基隆市| 三门峡市| 雅安市| 纳雍县| 沂源县| 赤城县| 东丽区| 左云县|