智能指針

說起指針相信大家一定不陌生,那麼智能指針呢?

首先,我們來看看,爲什麼要有智能指針?

例如

void Test2 ()
{
     int* p1 = new int(2);
     bool isEnd = true;

     //...
     if (isEnd )
    {
          delete p1 ;
          return;
    }
     //...

     delete p1;
}

在我們開闢空間時,在不用時,應該將其釋放掉,但是代碼中經常會忘掉釋放動態開闢的資源,在碰到前面的邏輯處理時,也常常是如履薄冰,小心謹慎,儘管如此還是會一不小心就會泄漏,防不勝防,令人頭疼不已。那麼,就引出了智能指針的概念了。

什麼事智能指針呢?

所謂智能指針就是智能/自動化的管理指針所指向的動態資源的釋放。

我們看看庫中的智能指針

wKiom1c0kNmDaYRrAABJvo2d89o964.png

接下來,簡單實現一下主要的智能指針

#include<iostream>
using namespace std;
//template<class T>
//class AutoPtr
//{
//public:
//	AutoPtr(T* ptr)
//		:_ptr(ptr)
//	{}
//
//	AutoPtr( AutoPtr<T>& sp)
//	{
//		 _ptr = sp._ptr ;
//		sp._ptr = NULL;
//	}
//
//	~AutoPtr()
//	{
//		if(_ptr)
//		{
//			delete _ptr;
//		    _ptr = NULL;
//		}
//		
//	}
//
//	AutoPtr<T>& operator=(AutoPtr<T>& sp)
//	{
//		if(this != &sp)
//		{
//		 _ptr = sp._ptr ;
//		sp._ptr = NULL;
//		}
//	}
//	
//	
//	T& operator*()
//	{
//		return *_ptr;
//	}
//
//	T* operator->()
//	{
//		return _ptr;
//	}
//
//	T* GetPtr()
//	{
//		return _ptr;
//	}
//
//private:
//	T* _ptr;
//};
//
//template<class T>
//class ScoprPtr   //把拷貝構造和賦值運算符的重載方成私有或者保護
//{
//public:
//	ScoprPtr(T* ptr)
//		:_ptr(ptr)
//	{}
//
//	~ScoprPtr()
//	{
//		if(_ptr)
//		{
//			delete _ptr;
//		    _ptr = NULL;
//		}
//		
//	}
//
//	T& operator*()
//	{
//		return *_ptr;
//	}
//
//	T* operator->()
//	{
//		return _ptr;
//	}
//
//	T* GetPtr()
//	{
//		return _ptr;
//	}
//protected:
//	ScoprPtr<T>& ScoprPtr=(ScoprPtr<T>& sp);
//	ScoprPtr(ScoprPtr<T>& sp);
//private:
//	T* _ptr;
//
//};
template<class T>
class SharePtr         //引用計數的方法實現的
{
public:
	SharePtr(T* ptr)
		:_ptr(ptr)
		,_pcount(new int(1))
	{}
	SharePtr(SharePtr<T>& sp)
	{
		_ptr = sp._ptr;
		_pcount = sp._pcount;
		++*(sp._pcount);
	}
	~SharePtr()
	{
		if(--(*_pcount) == 0)
		{
			delete _ptr;
			delete _pcount;
		    _ptr = NULL;
			_pcount = NULL;
		}
		
	}
	SharePtr<T>& operator=(SharePtr<T>& sp)
	{
		if(this != &sp)
		{
		 _ptr = sp._ptr;
		_pcount = sp._pcount;
		++*(sp._pcount);
		}
	}
	/*SharePtr<T>& operator=(SharePtr<T> sp)
	{
		SharePtr<T> tem(sp);
		swap(_ptr,tem._ptr);
		swap(_pcount,tem._pcount);
	}*/
	
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	T* GetPtr()
	{
		return _ptr;
	}
private:
	T* _ptr;
	int* _pcount;
};

以上一共實現了三種智能指針,其餘的想要了解,可以去cplusplus上面看看。

知道了智能指針的種類和實現及其瞭解,我們幾下來就去看看,一些公司是如何對待智能指針的

wKiom1c0k4PinPxsAADufKD5eVU949.png

從上,可看出auto_ptr是被摒棄的,爲何呢?

因爲一個auto_ptr被拷貝或被賦值後, 其已經失去對原對象的所有權,這個時候,對這個auto_ptr的提領(dereference)操作是不安全的。

int*p=new int(0);
auto_ptr<int>ap1(p);
auto_ptr<int>ap2=ap1;
cout<<*ap1;//錯誤,此時ap1只剩一個null指針在手了

這種情況較爲隱蔽的情形出現在將auto_ptr作爲函數參數按值傳遞,因爲在函數調用過程中在函數的作用域中會產生一個局部對象來接收傳入的auto_ptr(拷貝構造),這樣,傳入的實參auto_ptr就失去了其對原對象的所有權,而該對象會在函數退出時被局部auto_ptr刪除。

或許大家會想到用auto_ptr的指針或引用作爲函數參數或許可以,但是仔細想想,我們並不知道在函數中對傳入的auto_ptr做了什麼, 如果當中某些操作使其失去了對對象的所有權, 那麼這還是可能會導致致命的執行期錯誤。

這就是爲何要摒棄auto_ptr的原因,一句話總結就是:避免潛在的內存崩潰問題。

最後如何選擇智能指針?

在掌握了這幾種智能指針後,大家可能會想另一個問題:在實際應用中,應使用哪種智能指針呢?

下面給出幾個使用指南。


(1)如果程序要使用多個指向同一個對象的指針,應選擇shared_ptr。這樣的情況包括:


有一個指針數組,並使用一些輔助指針來標示特定的元素,如最大的元素和最小的元素;

兩個對象包含都指向第三個對象的指針;

STL容器包含指針。很多STL算法都支持複製和賦值操作,這些操作可用於shared_ptr,但不能用於unique_ptr(編譯器發出warning)和auto_ptr(行爲不確定)。如果你的編譯器沒有提供shared_ptr,可使用Boost庫提供的shared_ptr。

(2)如果程序不需要多個指向同一個對象的指針,則可使用unique_ptr。如果函數使用new分配內存,並返還指向該內存的指針,將其返回類型聲明爲unique_ptr是不錯的選擇。這樣,所有權轉讓給接受返回值的unique_ptr,而該智能指針將負責調用delete。可將unique_ptr存儲到STL容器在那個,只要不調用將一個unique_ptr複製或賦給另一個算法(如sort())。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章