通俗易懂學習C++智能指針

智能指針是幹什麼的?

智能指針主要用於管理在堆上分配的內存,它將普通的指針封裝爲一個棧對象。當棧對象的生存週期結束後,會在析構函數中釋放掉申請的內存,從而防止內存泄漏node

什麼是內存泄漏?

內存泄漏指由於疏忽或錯誤形成程序未能釋放已經再也不使用的內存的狀況。內存泄漏並非指內存在物理上的消失,而是應用程序分配某段內存後,由於設計錯誤,失去了對該段內存的控制,於是
形成了內存的浪費。
ios

內存泄漏有什麼危害?

長期運行的程序出現內存泄漏,影響很大,如操做系統、後臺服務等等,出現內存泄漏會致使響應愈來愈慢,最終卡死網絡

智能指針的原理

對象構造時獲取資源,接着控制對資源的訪問使之在對象的生命週期內始終保持有效,最後在對象析構的時候釋放資源函數

咱們實際上把管理一份資源的責任託管給了一個對象。這種作法有兩大好處:this

  • 不須要顯式地釋放資源。
  • 採用這種方式,對象所需的資源在其生命期內始終保持有效。
智能指針的原理:
  1. RAII特性(是一種利用對象生命週期來控制程序資源(如內存、文件句柄、網絡鏈接、互斥量等等)的簡單技術)
  2. 重載operator*和opertaor->,具備像指針同樣的行爲。

auto_ptr指針

auto_ptr智能指針的缺點:當對象拷貝或者賦值後,前面的對象就懸空了spa

auto_ptr智能指針的模擬實現
template<class T>
class Auto_ptr{
public:
	Auto_ptr(T* ptr=nullptr):_ptr(ptr){}
	~Auto_ptr(){
		if (_ptr)
		delete _ptr;
	}
	Auto_ptr(Auto_ptr<T> &s)//拷貝構造會釋放s對象的指針,形成s指針與管理對象斷開聯繫
		:_ptr (s._ptr){
		s._ptr = NULL;
	}
	Auto_ptr<T>& operator=(Auto_ptr<T>& s){
		if (this != &s._ptr){
			if (_ptr)
				delete _ptr;
			_ptr = s._ptr;
			s._ptr = NULL;
		}
		return *this;
	}
	T& operator*(){
		return *_ptr;
	}
	T* operator->(){
		return _ptr;
	}
private:
	T* _ptr;
};

unique_ptr指針

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

template<class T>
class Unique_ptr{
public:
	Unique_ptr(T* ptr=nullptr):_ptr(ptr){}
	~Unique_ptr(){
		if (_ptr)
		delete _ptr;
	}
	T& operator*(){
		return *_ptr;
	}
	T* operator->(){
		return _ptr;
	}
private:
	Unique_ptr(Unique_ptr<T> &s)
		:_ptr(s._ptr){
		s._ptr = NULL;
	}
	Unique_ptr<T>& operator=(Unique_ptr<T>& s){
		if (this != &s._ptr){
			if (_ptr)
				delete _ptr;
			_ptr = s._ptr;
			s._ptr = NULL;
		}
		return *this;
	}
private:
	T* _ptr;
};

shared_ptr指針

shared_ptr的原理:經過引用計數的方式來實現多個shared_ptr對象之間共享資源。設計

  1. shared_ptr在其內部,給每一個資源都維護了着一份計數,用來記錄該份資源被幾個對象共享。
  2. 在對象被銷燬時(也就是析構函數調用),就說明本身不使用該資源了,對象的引用計數減一。
  3. 若是引用計數是0,就說明本身是最後一個使用該資源的對象,必須釋放該資源;
  4. 若是不是0,就說明除了本身還有其餘對象在使用該份資源,不能釋放該資源,不然其餘對象就成野指針了。
模擬實現:
template<class T>
class Shared_ptr{
public:
	Shared_ptr(T* ptr) 
		:_ptr(ptr),_pMutex(new mutex),_pRefrCount(new int(1))
	{}
	~Shared_ptr(){
		Realse();
	}
	Shared_ptr(const Shared_ptr<T>& sp)
		:_ptr(sp._ptr), _pRefrCount(sp._pRefCount), _pMutex(sp._pMutex)
	{
		AddRefCount();
	}
	Shared_ptr<T>* operator=(const Shared_ptr<T>& sp){
		if (this != sp){
			Realse();
			_ptr = sp._ptr;
			_pRefrCount = sp._pRefrCount;
			_pMutex = sp._pMutex;
			AddRefCount();
		}
		return this;
	}
	T& operator*(){ return *_ptr; }
	T* operator->(){ return _ptr; }

	int UseCount(){ return *_pRefrCount; }
	T* Get(){ return _ptr; }
	void AddRefCount(){
		_pMutex.lock();
		++(*_pRefrCount);
		_pMutex.unlock();
	}
private:
	void Realse(){
		bool flag = false;
		_pMutex.lock();
		if (--(*_pRefrCount) == 0){
			delete _pRefCount;
			delete _ptr;
			flag = true;
		}
		_pMutex.unlock();
		if (flag == true);
		delete _pMutex;
	}
private:
	T* _ptr;
	int* _pRefrCount;
	mutex _pMutex;
};

weak_ptr指針

weak_ptr是配合shared_ptr而引入的一種智能指針來協助shared_ptr工做,它能夠從一個shared_ptr或另外一個weak_ptr對象構造,它的構造和析構不會引發引用記數的增長或減小。沒有重載*和->但可使用lock得到一個可用的shared_ptr對象。3d

實例:指針

#include<iostream>
#include<memory>
using namespace std;
struct ListNode
{
	int _data;
	weak_ptr<ListNode> _prev;
	weak_ptr<ListNode> _next;
	~ListNode(){ cout << "~ListNode()" << endl; }
};
int main()
{
	shared_ptr<ListNode> node1(new ListNode);
	shared_ptr<ListNode> node2(new ListNode);
	cout << node1.use_count() << endl;
	cout << node2.use_count() << endl;
	node1->_next = node2;
	node2->_prev = node1;
	cout << node1.use_count() << endl;
	cout << node2.use_count() << endl;
	system("pause");
	return 0;
}

在這裏插入圖片描述
總結:

  • 智能指針主要用於管理在堆上分配的內存,它將普通的指針封裝爲一個棧對象。當棧對象的生存週期結束後,會在析構函數中釋放掉申請的內存,從而防止內存泄漏
  • auto_ptr智能指針:當對象拷貝或者賦值後,前面的對象就懸空了。
  • unique_ptr智能指針:防止智能指針拷貝和複製。
  • shared_ptr智能指針:經過引用計數的方式來實現多個shared_ptr對象之間共享資源。
  • weak_ptr智能指針:能夠從一個shared_ptr或另外一個weak_ptr對象構造,它的構造和析構不會引發引用記數的增長或減小。
  • 對shared_ptr進行初始化時不能將一個普通指針直接賦值給智能指針,由於一個是指針,一個是類。能夠經過make_shared函數或者經過構造函數傳入普通指針。並能夠經過get函數得到普通指針。
相關文章
相關標籤/搜索