c++智能指針的使用,auto_ptr,shared_ptr

今天寫程序時想用智能指針與vector容器一起解決指針數組的成員管理問題。在我的程序中我用到了多個指針容器,這樣就導致了一個問題,這些指針容器的清空非常繁瑣,我不能僅僅調用一次clear就能完成,我需要每次從容器中取出一個元素,然後釋放掉這個元素所佔的內存,之後再清除掉指針,然後再清空容器。我覺得很是麻煩,於是想將其改進,我不需要去管理容器內的這些指針,當容器被清空或者銷燬時,我希望這些元素所佔的內存也都被釋放掉。於是,我想到了智能指針,現將今天的整個過程記錄下來,以免日後再犯同樣的錯誤,同時也希望爲存在同樣疑惑的同學通俗的說明這個問題。

所謂智能指針,我所理解的就是其能夠判斷該指針的生存週期,在指針的生存週期外對其所佔用的內存進行自動釋放,而不需要程序員進行主動控制。對於c++的智能指針,我首先想到的是《Thingking in C++》中提到的auto_ptr,於是我就首先想採用auto_ptr來實現。首先定義一個類,重載new和delete操作符,以便我們能看到具體在使用過程中發生了什麼。

class CSmart
{
public:
	CSmart(void);
	~CSmart(void);
	CSmart(int i):i(i){}
private:
	int i;
public:
	static void * operator new(size_t size){
		void *p = ::operator new(size);
		cout<<"Allocting TraceHeap object on the heap at address "<<p<<endl;
		return p;
	}
	static void  operator delete(void *p){
		cout<<"Deleting TraceHeap object at address "<<p<<endl;
		::operator delete (p);
	}
	int getVal() const { return i ;}
};
然後我們首先來試驗下auto_ptr的作用

void test_smart_ptr()
{
	auto_ptr<CSmart> pCSmart(new CSmart(5));
	cout<<pCSmart->getVal()<<endl;
}
int main()
{
 test_smart_ptr();
system("pause");
return 0;
}
輸入結果如下:

我們看到在程序運行結束的時候申請的那塊內存被成功釋放,程序員並沒有主動釋放。好的,這正是我們想要的功能,那麼我們試試賦值的結果,我們把test_smart_ptr的代碼改爲如下內容:

void test_smart_ptr()
{
	auto_ptr<CSmart> pCSmart(new CSmart(5));
	cout<<"ori "<<pCSmart->getVal()<<endl;

	auto_ptr<CSmart> pCopy;
	pCopy = pCSmart;

	cout<<"copy "<<pCopy->getVal()<<endl;

	//cout<<pCSmart->getVal()<<endl;//Error! 內存讀取錯誤
}

我們發現ok,這一切都是沒有問題的,那麼我們把上面代碼中註釋掉的那一行取消掉註釋會是什麼樣的結果呢?

我們發現出現了錯誤,程序不能運行了,這可如何是好,從錯誤中我們大概知道是讀取了非法的內存地址,那麼爲什麼會出現這樣的情況呢,原來是C++標準中定義的auto_ptr中對“=”操作符重載的定義中時將賦值後的值搶奪掉原有值的管理所有權,這樣就導致了原有值的不可用。這樣,我們自然就想到了本來我們要解決的指針容器自動管理的問題,我們知道在向容器中添加元素的時候,其實就是賦值的操作,現在由於“=”問題,導致其不可用。看來,auto_ptr這個東西在一個函數內作爲臨時變量是比較好用的,其餘的就不那麼好用了,在好多資料上關於auto_ptr的使用有這麼幾點說明:

1、auto_ptr不能共享所有權。
2、auto_ptr不能指向數組
3、auto_ptr不能作爲容器的成員。
4、不能通過賦值操作來初始化auto_ptr
std::auto_ptr<int> p(new int(42));     //OK
std::auto_ptr<int> p = new int(42);    //ERROR
這是因爲auto_ptr 的構造函數被定義爲了explicit
5、不要把auto_ptr放入容器

那麼,還有沒有其他方法解決本文最開始的問題呢,肯定是有的,於是我們發現了shared_ptr,shared_ptr原來是Boost庫中的內容,現在c++11新標準的發佈,將其加入到了c++標準庫中,可以不必使用Boost庫而直接使用。那麼我們來改寫上面的例子:

void test_smart_ptr()
{
	shared_ptr<CSmart> pCSmart(new CSmart(5));
	cout<<"ori "<<pCSmart->getVal()<<endl;

	shared_ptr<CSmart> pCopy;
	pCopy = pCSmart;

	cout<<"copy "<<pCopy->getVal()<<endl;

	cout<<"ori again "<<pCSmart->getVal()<<endl;
}
結果如下:


我們發現一切正常,好的,那麼我們來用容器和只能指針實現對指針容器的管理吧。

void test_smart_ptr()
{
	vector<shared_ptr<CSmart>> smart_ptr_vector;

	shared_ptr<CSmart> pCSmart1(new CSmart(5));
	shared_ptr<CSmart> pCSmart2(new CSmart(10));
	shared_ptr<CSmart> pCSmart3(new CSmart(15));

	smart_ptr_vector.push_back(pCSmart1);
	smart_ptr_vector.push_back(pCSmart2);
	smart_ptr_vector.push_back(pCSmart3);


	for(vector<shared_ptr<CSmart>>::iterator it = smart_ptr_vector.begin();it != smart_ptr_vector.end(); it++)
		cout<<(*it)->getVal()<<endl;//訪問其中的每一個元素
}
ok,看運行結果,一切正常,這就是我們要的結果,之後可以按照vector中存入的爲普通變量進行處理。



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