智能指針,顧名思義,也就是自動回收內存的指針形式,不用程序員刻意去釋放,提高軟件開發效率,同時也會提高軟件魯棒性。
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。
關於智能指針相關的概念不多,重要的是熟練運用。