C++_智能指針

講這個(gè)之前,先來看一個(gè)例子:

十余年專注建站、設(shè)計(jì)、互聯(lián)網(wǎng)產(chǎn)品按需定制設(shè)計(jì)服務(wù),業(yè)務(wù)涵蓋品牌網(wǎng)站設(shè)計(jì)、商城網(wǎng)站建設(shè)小程序設(shè)計(jì)、軟件系統(tǒng)開發(fā)、成都App制作等。憑借多年豐富的經(jīng)驗(yàn),我們會(huì)仔細(xì)了解每個(gè)客戶的需求而做出多方面的分析、設(shè)計(jì)、整合,為客戶設(shè)計(jì)出具風(fēng)格及創(chuàng)意性的商業(yè)解決方案,創(chuàng)新互聯(lián)更提供一系列網(wǎng)站制作和網(wǎng)站推廣的服務(wù),以推動(dòng)各中小企業(yè)全面信息數(shù)字化,并利用創(chuàng)新技術(shù)幫助各行業(yè)提升企業(yè)形象和運(yùn)營效率。

void Test1 ()
{
    int* p1 = new int(2);
    //...
    try 
    {   
      DoSomeThing();
    }
    catch(...)
    {
      delete p1 ;
      throw;
    }
    //...
    delete p1 ;
}

這個(gè)例子,是通過C++異常處理機(jī)制,來管理動(dòng)態(tài)開辟出來的內(nèi)存,這是可以做到的。但是以后在開發(fā)軟件產(chǎn)品時(shí),需要開辟動(dòng)態(tài)內(nèi)存,你都這樣處理,就顯得非常繁瑣,代碼量也會(huì)加大,有時(shí)候邏輯會(huì)理不清楚,于是有人提出能不能將“動(dòng)態(tài)內(nèi)存擁有權(quán)”這個(gè)問題的復(fù)雜性,從軟件產(chǎn)品本身的復(fù)雜性中分離出來,由專門的人或團(tuán)隊(duì)來負(fù)責(zé)實(shí)現(xiàn),實(shí)際上是非常有利于軟件的模塊化和復(fù)用性的。畢竟,從本質(zhì)上來看,動(dòng)態(tài)內(nèi)存的擁有權(quán)和一款軟件產(chǎn)品本身所要解決的目標(biāo)問題在相當(dāng)大程度上是正交的,將其分解開來,分而治之從軟件工程學(xué)的角度來看實(shí)在是個(gè)不錯(cuò)的選擇。也顯得非常繁瑣,那C++為了處理這個(gè)問題,提出了一個(gè)叫RAII(Resource Acquisition Is Initialization)。

RAII:資源分配即初始化,定義一個(gè)類來封裝資源的分配和釋放,在構(gòu)造函數(shù)完成資源的分配和初始化,在析構(gòu)函數(shù)完成資源的清理,可以保證資源的正確初始化和釋放。這個(gè)類具體到下面的智能指針。

智能指針:所謂智能指針就是智能\自動(dòng)化管理動(dòng)態(tài)開辟內(nèi)存的釋放。

智能指針設(shè)計(jì)思想:首先提供一個(gè)類,然后用這個(gè)類去封裝原生指針,并且封裝類會(huì)提供客戶端代碼通常會(huì)施加在原生指針上的絕大多數(shù)操作接口。這樣,在保證跟原生指針相近的操作體驗(yàn)的同時(shí),簡(jiǎn)化了動(dòng)態(tài)內(nèi)存的管理負(fù)擔(dān)。

在C++11之前,標(biāo)準(zhǔn)庫中,只有一個(gè)auto_ptr,下面是模擬實(shí)現(xiàn)auto_ptr舊版本.

/*舊版本*/

/*實(shí)現(xiàn)原理:通過擁有者的改變來最后確定是否析構(gòu)對(duì)象*/

#include <iostream>

using namespace std;

template<class T>
class AutoPtr
{
public:
	AutoPtr(T* ptr)
		:_ptr(ptr)
	{
		_owner = true;
	}
	AutoPtr(AutoPtr<T>& ap)
		:_ptr(ap._ptr),_owner(ap._owner)
	{
		ap._owner = false;
	}
	AutoPtr<T>& operator=(AutoPtr<T>& ap)
	{
		if(this != &ap)
		{
			if(_owner)
			{
				delete _ptr;
			}
			_ptr = ap._ptr;
			_owner = ap._owner;
			if(ap._owner)
			{
				ap._owner = false;
			} 
		}
		return *this;
	}
	~AutoPtr()
	{
		if(_owner)
		{
			delete _ptr;
		}
	}
public:
	T& operator*()
	{
		return *_str;
	}
	T* operator ->()
	{
		return _str;
	}
private:
	T* _ptr;
	bool _owner;
};
void Test1()
{
	AutoPtr<int> ap1(new int(1));
	AutoPtr<int> ap2(ap1);
	AutoPtr<int> ap3(new int(3));
	ap3 = ap2;
}
int main()
{
	Test1();
	return 0;
}

顯示結(jié)果:

C++_智能指針

這樣看結(jié)果是對(duì)的,但是看下面這個(gè)Test2()

void Test2()
{
	AutoPtr<int> ap1(new int(1));
	AutoPtr<int> ap2(ap1);
	AutoPtr<int> ap3(new int(3));
	AutoPtr<int> ap4(ap3);
	ap4 = ap1;
}

顯示結(jié)果:

C++_智能指針

看上面就出現(xiàn)問題了,你把a(bǔ)p1 賦給 ap4 ,但是ap4的_owner 是 false ,這就是有問題的。到最后,ap4只是指向共有的那塊空間而已,沒有達(dá)到真正的管理,再看Test3()

void Test3()
{
	AutoPtr<int> ap1(new int(1));
	if(1)
	{
		AutoPtr<int> ap2(ap1);
	}
	*ap1 = 10;
}

顯示結(jié)果:

C++_智能指針

程序直接崩潰了,因?yàn)楫a(chǎn)生了野指針的訪問,訪問的那一塊空間已經(jīng)釋放了,所以就會(huì)崩潰了,正是由于舊版本有這諸多的問題,C++改進(jìn)了一下他,使他變得很“強(qiáng)大”,下來看模擬實(shí)現(xiàn):

/*新版本*/

/*實(shí)現(xiàn)原理:管理權(quán)的轉(zhuǎn)交*/

#include <iostream>
using namespace std;
 
template <class T>
class AutoPtr
{
public:
	AutoPtr(T* str)
		:_str(str)
	{}
	AutoPtr(AutoPtr<T>& ap)
		:_str(ap._str)
	{
		ap._str = NULL;
	}
	AutoPtr<T>& operator=(AutoPtr<T>& ap)
	{
		if(this != &ap)
		{
			delete _str;
			_str = ap._str;
			ap._str = NULL;
		}
		return *this;
	}
	~AutoPtr()
	{
		if(_str)
			delete _str;
	}
public:
	T& operator*()
	{
		return *_str;
	}
	T* operator ->()
	{
		return _str;
	}
private:
	T* _str;
};
 
struct A
{
	int _a;
};

void Test4()
{
    AutoPtr<int>ap(new int(1));
    AutoPtr<int>ap2(ap);
    AutoPtr<int>ap3(new int(2));
    AutoPtr<int>ap4(ap3);
    ap4 = ap;
}

int main()
{
    Test4();
    return 0;
}

顯示結(jié)果:

C++_智能指針

當(dāng)然這個(gè)結(jié)果是正確的,但是你要這個(gè)AutoPtr又有什么用,你用對(duì)象之間拷貝構(gòu)造新對(duì)象和對(duì)象之間相互賦值時(shí),就是為了讓他們共同管理,但是現(xiàn)在,這就有點(diǎn)low了,既沒有達(dá)到那種共同管理,也在拷貝構(gòu)造對(duì)象和相互賦值時(shí),不清不楚,那么他就相當(dāng)low。一些C++技術(shù)大牛,在開源庫函數(shù)boost庫(可移植的函數(shù)庫)中引出了新的智能指針,受到廣大編程愛好者的一致好評(píng)。于是在C++11標(biāo)準(zhǔn)引出了新的智能指針,unique_ptr,shared_ptr,weak_ptr。

模擬實(shí)現(xiàn)unique_ptr:

#include <iostream>

using namespace std;

template <class T>
class UniquePtr
{
public:
	UniquePtr(T* ptr)
		:_ptr(ptr)
	{}
	~UniquePtr()
	{
		if(_ptr != NULL)
		{
			delete _ptr;
		}
	}
protected:
	UniquePtr(UniquePtr<T>& up);
	UniquePtr<T> operator=(UniquePtr<T>& up);
public:
	T* operator*()
	{
		return *_ptr;
	}
	T& operator->()
	{
		return _ptr;
	}
private:
	T* _ptr;
};

void Test1()
{
        UniquePtr<int> up1(new int(1));
        UniquePtr<int> up2(new int(2));
}

int main()
{
	Test1();
	return 0;
}

顯示結(jié)果:

C++_智能指針

沒毛病,下來看test2():

void test2()
{
        UniquePtr<int> up1(new int(1));
	UniquePtr<int> up2(new int(2));
	up2 = up1;
	UniquePtr<int> up3(up1);
}

顯示結(jié)果:

C++_智能指針在編譯的時(shí)候出現(xiàn)了問題,這是為什么呢?

protected:
	UniquePtr(UniquePtr<T>& up);
	UniquePtr<T> operator=(UniquePtr<T>& up);

由于在類中只聲名拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載,不實(shí)現(xiàn),防止調(diào)用默認(rèn)的拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載造成淺拷貝的問題,加上保護(hù)限制,防止在被繼承時(shí),對(duì)其進(jìn)行重寫。避免了auto_ptr出現(xiàn)的問題,我unique_ptr就是不讓被復(fù)制和賦值,他是一種防拷貝(你就是霸道)的實(shí)現(xiàn),沒有像auto_ptr那樣轉(zhuǎn)移管理權(quán),直接就是我的就是我的,你們其他人邊去,但是我們也想要實(shí)現(xiàn)向原生指針那樣共同管理,那就可以shared_ptr,模擬實(shí)現(xiàn)shared_ptr:

#include <iostream>

using namespace std;

template <class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr)
		:_ptr(ptr),_pcount(new int(1))
	{
		cout<<"SharedPtr(T* ptr)"<<endl;
	}
	~SharedPtr()
	{
		cout<<"~SharedPtr()"<<endl;
		_Release();
	}
	SharedPtr(SharedPtr<T>& sp)
		:_ptr(sp._ptr),_pcount(sp._pcount)
	{
		cout<<"SharedPtr(SharedPtr<T>& sp)"<<endl;
		++(*_pcount);
	}
	SharedPtr<T>& operator= (SharedPtr<T> sp)//傳值,賦值前調(diào)用拷貝構(gòu)造函數(shù)
	{
		cout<<"SharedPtr<T>& operator="<<endl;
		swap(_ptr, sp._ptr);
		swap(_pcount, sp._pcount);
		return *this;
	}
public:
        /*接口函數(shù)*/
	T& operator*()//提供*接口
	{
		return *_ptr;
	}
	T* operator->()//提供->接口
	{
		return _ptr;
	}
public:
	int UseCount()
	{
		return *_pcount;
	}
	T* GetPtr()
	{
		return _ptr;
	}
protected:
	void _Release()
	{
		if(--(*_pcount) == 0)
		{
			delete _ptr;
			delete _pcount;
		}
	}
private:
	T* _ptr;
	int* _pcount;
};
int main()
{
	SharedPtr<int> sp(new int(1));
	SharedPtr<int> sp1(sp);
	SharedPtr<int> sp2(new int(2));
	SharedPtr<int> sp3(new int(3));
	sp3 = sp2;
	int count = sp2.UseCount();
	return 0;
}

顯示結(jié)果:

C++_智能指針

C++_智能指針

第一次構(gòu)造函數(shù):

SharedPtr<int> sp(new int(1));

第一次拷貝構(gòu)造函數(shù):

SharedPtr<int> sp1(sp);

第二次,第三次構(gòu)造函數(shù):

SharedPtr<int> sp2(new int(2));
SharedPtr<int> sp3(new int(3));

第二次拷貝構(gòu)造函數(shù),第一次賦值:

sp3 = sp2;

因?yàn)橘x值時(shí),采用傳值方式,所以調(diào)用拷貝構(gòu)造函數(shù)。

第一次析構(gòu)函數(shù),析構(gòu)臨時(shí)拷貝構(gòu)造出來的臨時(shí)對(duì)象。

第二次析構(gòu)函數(shù),析構(gòu)sp3,sp2(是共同管理一塊內(nèi)存的)。

第三次析構(gòu)函數(shù),析構(gòu)sp,sp1(是共同管理一塊內(nèi)存的)。

C++_智能指針完美...

是不是新的智能指針完美的解決auto_ptr的問題呢,對(duì),是的。所以在以后需要使用智能指針的時(shí)候,不要用auto_ptr,因?yàn)樗麄兺昝赖脑忈屧羔?,?dāng)不需要復(fù)制,賦值時(shí),應(yīng)該首選unique_ptr,需要復(fù)制和賦值就需要選擇shared_ptr.

當(dāng)前名稱:C++_智能指針
文章網(wǎng)址:http://bm7419.com/article44/jjeche.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、營銷型網(wǎng)站建設(shè)微信公眾號(hào)、建站公司軟件開發(fā)、ChatGPT

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設(shè)計(jì)公司