欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++11 智能指針的具體使用

 更新時間:2021年08月24日 11:06:06   作者:Reset。  
本文主要介紹了C++11 智能指針的具體使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

智能指針的原理

RAII

RAII(Resource Acquisition Is Initialization)是一種利用對象生命周期來控制程序資源(如內存、文件句柄、網絡連接、互斥量等等)的簡單技術。

在對象構造時獲取資源,接著控制對資源的訪問使之在對象的生命周期內始終保持有效,最后在對象析構的時候釋放資源。 借此,我們實際上把管理一份資源的責任托管給了一個對象。這種做法有兩大好處:

  • 不需要顯式地釋放資源。
  • 采用這種方式,對象所需的資源在其生命期內始終保持有效。

我們使用RAII的思想設計SmartPtr類:

template <class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}

    ~SmartPtr()
	{
		if (_ptr)
		{
			delete _ptr;
			_ptr = nullptr;
		}
	}

private:
	T* _ptr;
};

智能指針的原理

上述的SmartPtr還不能將其稱為智能指針,因為它還不具有指針的行為。指針可以解引用,也可以通過->去訪問所指空間中的內容 ,因此:SmartPtr模板類中還得需要將* 、->重載下,才可讓其像指針一樣去使用。

template <class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}

	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}

    ~SmartPtr()
	{
		if (_ptr)
		{
			delete _ptr;
			_ptr = nullptr;
		}
	}

private:
	T* _ptr;
};

智能指針使用:

在這里插入圖片描述

總結智能指針的原理:

  • RAII特性
  • 重載operator*和opertaor->,具有像指針一樣的行為。

auto_ptr

1.auto_ptr的使用及問題

auto_ptr的頭文件#include<memory>

auto_ptr的使用:

在這里插入圖片描述

在這里插入圖片描述

為什么此時訪問sp的成員時會報錯呢?我們來看看它們的地址。

在這里插入圖片描述

我們發(fā)現在拷貝構造之后,sp管理的地址為空,而sp1管理的地址是之前sp所管理的地址,管理權發(fā)生了轉移。那么上面所說的報錯也很容易想通,因為sp管理的地址為空,不能進行訪問。

auto_ptr的問題:當對象拷貝或者賦值后,管理權進行轉移,造成前面的對象懸空。auto_ptr問題是非常明顯的,所以實際中很多公司明確規(guī)定了不能使用auto_ptr。

auto_ptr的實現原理:管理權轉移的思想,下面簡化模擬實現了一份AutoPtr來了解它的原理:

template<class T>
class AutoPtr
{
public:
	AutoPtr(T* ptr)
		:_ptr(ptr)
	{}

	//拷貝:管理權轉移
	AutoPtr(AutoPtr<T> &sp)
		:_ptr(sp._ptr)
	{
		sp._ptr = nullptr;
	}

	//賦值:管理權轉移
	AutoPtr& operator=(AutoPtr<T> &sp)
	{
		if (this != &sp)
		{
			if (_ptr)
				delete _ptr;
			_ptr = sp._ptr;
			sp._ptr = nullptr;
		}
		return *this;
	}

	~AutoPtr()
	{
		if (_ptr)
		{
			delete _ptr;
			_ptr = nullptr;
		}
	}

	T* operator->()
	{
		return _ptr;
	}

	T& operator*()
	{
		return *_ptr;
	}

private:
	T* _ptr;
};

unique_ptr

為了解決拷貝或者賦值時管理權轉移的問題,出現了unique_ptr。

unique_ptr解決問題的方式非常粗暴:防拷貝,也就是不讓賦值和拷貝

unique_ptr的使用:

在這里插入圖片描述

unique_ptr的實現原理:簡單粗暴的防拷貝,下面簡化模擬實現了一份UniquePtr來了解它的原理:

template<class T>
class UniquePtr
{
public:

	UniquePtr(T* ptr)
		:_ptr(ptr)
	{}

	// C++11防拷貝的方式:delete
	UniquePtr(const UniquePtr<T> &) = delete;

	UniquePtr& operator=(const UniquePtr<T>&) = delete;

	T* operator->()
	{
		return _ptr;
	}

	T& operator*()
	{
		return *_ptr;
	}

	~UniquePtr()
	{
		if (_ptr)
		{
			delete _ptr;
			_ptr = nullptr;
		}
	}

private:

	//C++98防拷貝的方式:只聲明不實現+聲明成私有
	//UniquePtr(UniquePtr<T> const &);
	//UniquePtr& operator=(UniquePtr<T> const &);

	T* _ptr;
};

shared_ptr

c++11中提供更靠譜的并且支持拷貝的shared_ptr

shared_ptr的使用

在這里插入圖片描述

shared_ptr中拷貝與賦值都是沒有問題的。

shared_ptr的原理

  • shared_ptr的原理:是通過引用計數的方式來實現多個shared_ptr對象之間共享資源。shared_ptr在其內部,給每個資源都維護了著一份計數,用來記錄該份資源被幾個對象共享。
  • 對象被銷毀時(也就是析構函數調用),就說明自己不使用該資源了,對象的引用計數減一。
  • 如果引用計數是0,就說明自己是最后一個使用該資源的對象,必須釋放該資源;
  • 如果不是0,就說明除了自己還有其他對象在使用該份資源,不能釋放該資源,否則其他對象就成野指針了。

shared_ptr中成員函數:use_count(對象數據的引用計數)

示例:

在這里插入圖片描述

示例詳解:

在這里插入圖片描述

利用引用計數簡單的實現SharedPtr,了解原理:

template<class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr)
		:_ptr(ptr)
		,_count(new int(1))
	{}

	SharedPtr(const SharedPtr<T> &sp)
		:_ptr(sp._ptr)
		,_count(sp._count)
	{
		//計數器累加
		++(*_count);
	}

	SharedPtr& operator=(const SharedPtr<T> &sp)
	{
		//判斷管理的是否是同一份資源
		if (_ptr != sp._ptr)
		{
			//計數-1,判斷之前管理的資源是否需要釋放
			if ((--(*_count)) == 0)
			{
				delete _ptr;
				delete _count;
			}
			
			_ptr = sp._ptr;
			_count = sp._count;

			//計數器累加
			++(*_count);
		}
		return *this;
	}

	T* operator->()
	{
		return _ptr;
	}
	
	T& operator*()
	{
		return *_ptr;
	}

	~SharedPtr()
	{
		if (--(*_count) == 0)
		{
			delete _ptr;
			delete _count;
			_ptr = nullptr;
			_count = nullptr;
		}
	}

private:
	T* _ptr;
	int* _count;//給每份資源開辟一個計數器
};

但是還存在一個線程安全的問題:

  1. 智能指針對象中引用計數是多個智能指針對象共享的,兩個線程中智能指針的引用計數同時++或–,這個操作不是原子的,引用計數原來是1,++了兩次,可能還是2。這樣引用計數就錯亂了。會導致資源未釋放或者程序崩潰的問題。所以只能指針中引用計數++、- -是需要加鎖的,也就是說引用計數的操作是線程安全的。
  2. 智能指針管理的對象存放在堆上,兩個線程中同時去訪問,會導致線程安全問題。

這里我們通過加鎖來解決線程安全問題:

template<class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr)
		:_ptr(ptr)
		,_count(new int(1))
		,_mutex(new mutex)
	{}

	SharedPtr(const SharedPtr<T> &sp)
		:_ptr(sp._ptr)
		,_count(sp._count)
		,_mutex(sp._mutex)
	{
		//計數器累加
		AddCount();
	}

	SharedPtr& operator=(const SharedPtr<T> &sp)
	{
		//判斷管理的是否是同一份資源
		if (_ptr != sp._ptr)
		{
			//計數-1,判斷之前管理的資源是否需要釋放
			if (SubCount() == 0)
			{
				delete _ptr;
				delete _count;
				delete _mutex;
			}
			
			_ptr = sp._ptr;
			_count = sp._count;
			_mutex = sp._mutex;

				//計數器累加
			AddCount();
		}
		return *this;
	}

	//線程安全的累加器
	int AddCount()
	{
		//加鎖
		_mutex->lock();
		++(*_count);
		_mutex->unlock();
		return *_count;
	}

	int SubCount()
	{
		_mutex->lock();
		--(*_count);
		_mutex->unlock();
		return *_count;
	}

	T* operator->()
	{
		return _ptr;
	}
	
	T& operator*()
	{
		return *_ptr;
	}

	~SharedPtr()
	{
		if (SubCount() == 0)
		{
			delete _ptr;
			delete _count;
			delete _mutex;
			_ptr = nullptr;
			_count = nullptr;
			_mutex = nullptr;
		}
	}
	
private:
	T* _ptr;
	int* _count;//給每份資源開辟一個計數器
	mutex* _mutex; //每一份資源有一個獨立的鎖
};

shared_ptr的循環(huán)引用

循環(huán)引用的場景:

struct ListNode
{
	int _data; 
    shared_ptr<ListNode> _prev;
	shared_ptr<ListNode> _next;
	~ListNode() { cout << "~ListNode()" << endl; }
};

void test()
{
	shared_ptr<ListNode> node1(new ListNode);
	shared_ptr<ListNode> node2(new ListNode);

	node1->_next = node2;
	node2->_prev = node1;
} 

在這里插入圖片描述

node1和node2兩個智能指針對象指向兩個節(jié)點,兩個節(jié)點的引用計數都是1。node1->next指向node2,node2->prev指向node1,兩個節(jié)點的引用計數都變成2。程序運行完之后,析構node1和node2,node1和node2所指向的節(jié)點引用計數分別減1,但是node1->next指向下面節(jié)點,node2->prev指向上面節(jié)點,此時,兩個節(jié)點的引用計數都為1,所以兩個節(jié)點不能析構。

引用計數為0時,如果要析構node1節(jié)點,就先要去析構node1中的自定義結構,然后再析構node1。也就是說node1->next析構了,node2就釋放了;node2->prev析構了,node1就釋放了。但是_next屬于node的成員,node1釋放了,_next才會析構,而node1由_prev管理,_prev屬于node2成員,所以這就叫循環(huán)引用,誰也不會釋放。

解決方案:
在引用計數的場景下,把節(jié)點中的_prev和_next改成weak_ptr就可以了
原理就是,node1->_next = node2和node2->_prev = node1時weak_ptr的_next和_prev不會增加node1和node2的引用計數。

weak_ptr最大作用就是解決shared_ptr的循環(huán)引用

struct ListNode
{
	int _data; 
    weak_ptr<ListNode> _prev;
	weak_ptr<ListNode> _next;
	~ListNode() { cout << "~ListNode()" << endl; }
};
void test()
{
	shared_ptr<ListNode> node1(new ListNode);
	shared_ptr<ListNode> node2(new ListNode);

	node1->_next = node2;
	node2->_prev = node1;
} 

注意:
weak_ptr不能單獨使用,可以用shared_ptr創(chuàng)建

	//weak_ptr錯誤使用
	weak_ptr<ListNode> node1(new ListNode);

	//weak_ptr正確使用
	shared_ptr<ListNode> node2(new ListNode);
	weak_ptr<ListNode> node3(node2);

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

相關文章

  • 使用C語言實現掃雷小游戲

    使用C語言實現掃雷小游戲

    這篇文章主要為大家詳細介紹了使用C語言實現掃雷小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • C語言編程中從密碼文件獲取數據的函數總結

    C語言編程中從密碼文件獲取數據的函數總結

    這篇文章主要介紹了C語言編程中從密碼文件獲取數據的函數總結,包括getpw()函數和getpwnam()函數以及getpwuid()函數,需要的朋友可以參考下
    2015-08-08
  • C++?opencv利用grabCut算法實現摳圖示例

    C++?opencv利用grabCut算法實現摳圖示例

    這篇文章主要為大家介紹了C++?opencv利用grabCut算法實現摳圖的代碼示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • 使用c語言輕松實現動態(tài)內存管

    使用c語言輕松實現動態(tài)內存管

    這篇文章主要介紹了使用c語言輕松實現動態(tài)內存管,本文章內容詳細,具有很好的參考價值,希望對大家有所幫助,需要的朋友可以參考下
    2023-01-01
  • C語言去除相鄰重復字符函數的實現方法

    C語言去除相鄰重復字符函數的實現方法

    這篇文章主要介紹了C語言去除相鄰重復字符函數的實現方法的相關資料,實現去重字符串相鄰重復的字符,不相鄰的不用去重的功能,需要的朋友可以參考下
    2017-08-08
  • 一篇文章帶你了解C語言操作符

    一篇文章帶你了解C語言操作符

    這篇文章主要以圖文結合的方式為大家詳細介紹了C語言操作符基礎知識,感興趣的小伙伴們可以參考一下,希望能給你帶來幫助
    2021-09-09
  • c++ Protobuf解決數據傳輸瓶頸面試精講

    c++ Protobuf解決數據傳輸瓶頸面試精講

    這篇文章主要介紹了c++ Protobuf解決數據傳輸瓶頸利器面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • VisualStudio2022 cmake配置opencv開發(fā)環(huán)境

    VisualStudio2022 cmake配置opencv開發(fā)環(huán)境

    本文主要介紹了VisualStudio2022 cmake配置opencv開發(fā)環(huán)境,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-08-08
  • 詳解C++中多態(tài)的底層原理

    詳解C++中多態(tài)的底層原理

    要了解C++多態(tài)的底層原理需要我們對C指針有著深入的了解,這個在打印虛表的時候就可以見功底,所以快來跟隨小編一起學習一下吧
    2022-04-04
  • C++有限狀態(tài)機實現詳解

    C++有限狀態(tài)機實現詳解

    這篇文章主要為大家詳細介紹了C++有限狀態(tài)機的相關資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10

最新評論