C++11:智能指針

智能指針,顧名思義,也就是自動回收內存的指針形式,不用程序員刻意去釋放,提高軟件開發效率,同時也會提高軟件魯棒性。

C++11一共有4個智能指針,分別爲auto_ptr、unique_ptr、shared_ptr、weak_ptr。其中auto_ptr由於存在設計問題,被標記爲“已棄用”,將在未來某個C++版本中被移除。本文主要介紹其他三個指針形式。使用前首先包含 <memory>這個頭文件

1、unique_ptr

這個智能指針的含義爲,智能指針所管理的內存區域爲獨佔狀態,當另一個unique_ptr訪問當前指針時,當前指針會失效,內存的控制權交給新指針。示例如下:

#include <iostream>
#include <memory>
using namespace std;

void test_ptr (unique_ptr<int> p) {
}

int main (int argc, char* argv []) {
	//構造一個unique_ptr
	unique_ptr<int> p = make_unique<int> (5);
	//打印指針內容
	cout << *p << endl;
	//修改指針內容
	*p = 100;
	//打印指針內容
	cout << *p << endl;
	//將控制權交給函數參數
	test_ptr (move (p));
	//測試指針是否有效
	cout << p.get () << endl;
	return 0;
}
首先構造一個unique_ptr。unique_ptr構造方式以前一般爲 unique_ptr<int> p (new int); 這樣的形式,構造時直接包含一個指針。後來在C++14中引入了make_unique,建議統一寫成這樣的格式。
構造時設置初始值爲5,打印結果也爲5,然後設置指針內容爲100,這兒打印出來的結果也爲100,然後使用移動語義,將控制權交給test_ptr函數,這時候main函數中p指針失效,然後函數什麼也不做,當它返回時,實際上已經將指針指向的內存釋放了。然後我們調用 get() 函數獲取智能指針管理的指針地址,打印結果爲00000000

可見智能指針用法上還是很簡單的。


2、shared_ptr

這是一個最像智能指針的智能指針,同時也是使用最爲廣泛的智能指針。示例代碼如下:

#include <iostream>
#include <memory>
using namespace std;

void test_ptr (shared_ptr<int> p) {
	//顯示當前引用個數
	cout << p.use_count () << endl;
}

int main (int argc, char* argv []) {
	//構造一個shared_ptr
	shared_ptr<int> p = make_shared<int> (5);
	//調用函數,增加引用計數
	test_ptr (p);
	//顯示當前引用個數
	cout << p.use_count() << endl;
	//顯示指針是否有效
	cout << p.get () << endl;
	return 0;
}
構造方式與unique_ptr大同小異,不過make_shared是C++11就已經存在的shared_ptr智能指針標準構造方式。

然後我們調用函數,這時候p的引用計數+1(主函數有一個引用,test_ptr函數有一個引用),打印引用數量,結果爲2。函數調用完成後,智能指針引用計數-1,這時候我們再打印引用計數,結果爲1。然後我們再打印地址,顯示的爲有效地址,可能不同電腦上地址不一樣,只要不爲00000000,就代表智能指針還是有效的。關於shared_ptr指針的訪問方式與unique_ptr相同,這兒不再重複。

注:網神曾經說過,如果你用了智能指針,那麼你也就與引用無緣了。引用不會增加引用計數。

3、weak_ptr

這個指針用於配合shared_ptr,在不增加引用計數的前提下判斷shared_ptr是否有效。示例如下:

#include <iostream>
#include <memory>
using namespace std;

void test_ptr (weak_ptr<int> p) {
	//顯示引用是否失效
	cout << p.expired () << endl;
	//顯示當前引用個數
	cout << p.use_count () << endl;
	//通過weak_ptr構造shared_ptr
	shared_ptr<int> p2 = p.lock ();
	if (p2.get () != nullptr) {
		//顯示當前引用個數
		cout << p.use_count () << endl;
	}
}

int main (int argc, char* argv []) {
	//構造一個shared_ptr
	shared_ptr<int> p = make_shared<int> (5);
	//調用函數,不增加引用計數
	test_ptr (p);
	return 0;
}
這次我們把test_ptr參數改爲weak_ptr,構造它不增加引用計數。首先打印是否失效。由於main函數還存在一個引用,所以沒有失效,結果爲0,然後顯示當前引用個數,結果爲1,然後通過weak_ptr構造出shared_ptr並判斷構造出的是否有效。這個判斷在單線程環境下顯得有些多餘,不過養成良好的書寫習慣非常重要。判斷之後再顯示出weak_ptr的引用計數,這兒的結果爲2。


關於智能指針相關的概念不多,重要的是熟練運用。

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