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

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

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

一、RAII和智能指針

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

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

例:

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++標準庫智能指針的使用

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

C++標準庫主要提供了四種智能指針:
auto_ptr: 它是在C++98中設計出來的智能指針,其特點是拷貝時把被拷貝對象的資源管理權轉移給拷貝對象,這個設計是非常糟糕的,因為它會讓被拷貝的對象懸空,當我們對其進行訪問時會發(fā)生報錯。因此在日常工作中不建議使用這一指針

以下這三種指針都是在C++11中設計出來的
unique_ptr:它的意思是唯一指針,其特點是不支持拷貝只支持移動,因此在不需要拷貝的場景下就可以使用它

shared_ptr: 它的意思是共享指針,其特點是支持拷貝也支持移動,因此在需要拷貝的場景下就可以使用它

weak_ptr:它的意思的弱指針,其完全不同于上面的智能指針,因為它不支持RAII,也就意味著不能用它直接管理資源。其作用是用來解決循環(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的管理權轉移給ap2
	auto_ptr<Date> ap2(ap1);
	//報錯:對空指針進行訪問
	ap1->_year++;
	unique_ptr<Date> up1(new Date);
	//報錯:不支持拷貝
	unique_ptr<Date> up2(up1);
	//支持移動,移動后up1也為空,不能對其進行訪問
	unique_ptr<Date> up2(move(up1));
	shared_ptr<Date> sp1(new Date);
	//支持拷貝也支持移動
	shared_ptr<Date> sp2(sp1);
	shared_ptr<Date> sp3(move(sp1));
	return 0;
}

刪除器

智能指針析構時默認是進行delete釋放資源,這也就意味著如果不是new出來的資源交給智能指針管理,析構時就會崩潰。因此智能指針支持在構造時給?個刪除器,而刪除器本質就是?個可調用對象,這個可調用對象中實現你想要的釋放資源的方式。即當我們在構造智能指針時,給了定制的刪除器,智能指針析構時就會調用我們設計出的刪除器去釋放資源

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()
{
	//這樣去構造程序會報錯
	//unique_ptr<Date> up(new Date[10]);
	//shared_ptr<Date> sp(new Date[10]);
	//解決方案1:因為new[]經常使用,因此unique_ptr和shared_ptr 
    //實現了?個特化版本,這個特化版本在析構時用的delete[] 
	unique_ptr<Date[]> up(new Date[10]);
	shared_ptr<Date[]> sp(new Date[10]);
	//解決方案2:使用仿函數對象做刪除器
	//這里需要注意:unique_ptr和shared_ptr在支持刪除器的方式是有所不同的
	//unique_ptr在類模板參數支持的,shared_ptr是構造函數參數支持的 
	unique_ptr<Date, DeleteArray<Date>> up1(new Date[10]);
	shared_ptr<Date> sp1(new Date[10], DeleteArray<Date>());
	// 函數指針做刪除器  
	unique_ptr<Date, void(*)(Date*)> up3(new Date[5], DeleteArrayFunc<Date>);
	shared_ptr<Date> sp3(new Date[5], DeleteArrayFunc<Date>);
	// lambda表達式做刪除器 
	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;
}

使用時需要注意以下幾點:
1.shared_ptr 除了支持用指向資源的指針構造,還支持 make_shared 用初始化資源對象的值直接構造。

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

3.shared_ptr 和 unique_ptr 在構造函數中都得使用explicit來修飾,防止普通指針隱式類型轉換成智能指針對象。

例:

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;
}

三、智能指針的原理及其模擬實現

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是防止普通指針隱式類型
		// 	轉化為智能指針對象
		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;
		}
		//不支持左值的拷貝構造
		unique_ptr(const unique_ptr<T>& up) = delete;
		//不支持左值的賦值
		unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;
		//支持右值的拷貝構造
		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.重點:shared_ptr

shared_ptr的拷貝底層是采用引用計數的方式來實現的,讓多個shared_ptr對象共用同一份資源

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之間的關系

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

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

當n1和n2進行析構時,引用計數為1不為0,導致內存泄漏

2.weak_ptr的介紹及其模擬實現

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

• weak_ptr也沒有重載operator*和operator->等,因為它不參與資源管理,但如果它綁定的shared_ptr已經釋放了資源,我們在對其進行訪問,那是非常危險的。因此它設計出expired幫助我們檢查指向的資源是否過期,使用use_count也可獲取shared_ptr中的引用計數

例:

五、C++11和boost智能指針中的關系

Boost庫是為C++語言標準庫提供擴展的?些C++程序庫的總稱,C++11及之后的新語法和庫有很多都是從Boost中來的

C++98中產生了第?個智能指針auto_ptr

C++boost庫也給出了更實用的scoped_ptr/scoped_array和shared_ptr/shared_array和weak_ptr等

C++TR1,引入了shared_ptr等,不過注意的是TR1并不是標準版

C++11,引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr對應boost的scoped_ptr。并且這些智能指針的實現原理是參考boost中的實現的

六、內存泄漏

1.什么是內存泄漏以及造成的危害

內存泄漏指因為疏忽或錯誤造成程序未能釋放已經不再使用的內存,?般是忘記釋放或者發(fā)生異常釋放程序未能執(zhí)行導致的。

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

2.如何避免內存泄漏

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

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

3.定期使用內存泄露工具

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

相關文章

  • 鏈接庫動態(tài)鏈接庫詳細介紹

    鏈接庫動態(tài)鏈接庫詳細介紹

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

    C語言中常見的幾種流程控制語句

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

    C++ 構造函數和析構函數示例詳解

    本文詳細介紹了C++中的構造函數和析構函數,包括它們的特點、調用時機以及在資源管理中的重要性,同時,通過與Python的對比,展示了如何在Python中模擬C++的構造函數特性,并強調了兩種語言在內存管理和資源管理機制上的差異,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • 使用Matlab制作簡易版八分音符醬游戲

    使用Matlab制作簡易版八分音符醬游戲

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

    C++Smart Pointer 智能指針詳解

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

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

    C++?STL(標準模板庫)是一套功能強大的?C++?模板類,提供了通用的模板類和函數,這些模板類和函數可以實現多種流行和常用的算法和數據結構,如向量、鏈表、隊列、棧,今天我們來探究一下stl容器適配器的使用吧
    2021-11-11
  • 基于OpenCV讀取攝像頭實現單個人臉驗證MFC程序

    基于OpenCV讀取攝像頭實現單個人臉驗證MFC程序

    這篇文章主要為大家詳細介紹了基于OpenCV讀取攝像頭實現單個人臉驗證MFC程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • C語言浮點型數據在內存中的存儲方式詳解

    C語言浮點型數據在內存中的存儲方式詳解

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

    詳解C++中inline關鍵字的作用

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

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

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

最新評論

桑日县| 巩留县| 贵溪市| 砀山县| 陵川县| 白朗县| 海安县| 周至县| 宽城| 龙门县| 资溪县| 陆良县| 汽车| 海兴县| 永修县| 梓潼县| 绥德县| 秦皇岛市| 进贤县| 夏邑县| 凌海市| 全南县| 卓资县| 白银市| 房产| 钟山县| 静安区| 南投县| 商都县| 儋州市| 定远县| 清涧县| 运城市| 马关县| 南通市| 大邑县| 九龙城区| 裕民县| 德州市| 曲麻莱县| 西华县|