智慧指針(smart pointer)是C++11
以後出的有關自動釋放資源(記憶體)的函式庫,就是C#
, JAVA
的GC的功能
我們的程式每次啟動,都會向作業系統(OS)要記憶體來存放跟使用資料,這其中有兩種的記憶體存放方式,堆
、棧
跟資料結構堆積 Heap
名稱很像,但是是不同的東西,這個區塊主要是由使用者分配跟釋放的,如果沒釋放或釋放不乾淨,就有可能導致內存洩漏 Memory Leak
,引發程式崩潰,而堆的記憶體位址是從較低位址往高位址
這個區塊是屬於區域變數的資料,像我們函式裡面的變數就是存放在這區,當離開函式,區域變數的資料都會被系統清掉,不用介入,而棧的記憶體是從較高位址到較低位址的
接下來就是介紹C++11
出的三種智慧指針類型:shared_ptr
, unique_ptr
, weak_ptr
shared_ptr
算是最常用的,其中的實作就是對資源引用作記數,引用記數為0的時候,就會自動釋放資源,參考下面例子
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Cat
{
public:
Cat() {}
Cat(string name, int tail):Name(name), TailLen(tail) {}
~Cat()
{
cout << "Cat " << Name << " free\n";
}
string Name = "";
int TailLen = 0;
};
int main(int argc, char const *argv[])
{
// 建議用make_shared替代new,因為分配記憶體的位址會有優化,記憶體分配較連續,對性能好
shared_ptr<Cat> pCat = make_shared<Cat>("cat1", 49);
cout << "pCat count: " << pCat.use_count() << endl;
{
shared_ptr<Cat> pCat2 = pCat;
cout << "pCat count: " << pCat.use_count() << endl;
// Cat2跟Cat是同一個物件,離開時引數為1,還不會自動釋放
}
cout << "pCat count: " << pCat.use_count() << endl;
{
shared_ptr<Cat> pCat3 = make_shared<Cat>("cat3", 55);
// 會比cat1先釋放,離開作用域,引數就為0
}
return 0;
}
unique_ptr
比shared_ptr
不一樣的是,unique_ptr
的指標是唯一的,也就是不能被複製,而因為只能是唯一,性能方面也會比shared_ptr
好,參考下面例子
int main(int argc, char const *argv[])
{
// make_unique是C++14才有的語法
unique_ptr<Cat> pCat4 = make_unique<Cat>("cat4", 16);
// 下面會編譯錯誤
// unique_ptr<Cat> pCat5 = pCat4;
// 但可以透過move去轉移擁有權,move下次再介紹
unique_ptr<Cat> pCat6 = move(pCat4); // cat4就不能用了
// move也能將unique_ptr轉成shared_ptr,但不能將shared_ptr轉成unique_ptr
shared_ptr<Cat> pCat7 = move(pCat6);
return 0;
}
weak_ptr
是搭配shared_ptr
,用來檢查資源被釋放了沒,並不影響資源的記數,參考下面例子
int main(int argc, char const *argv[])
{
weak_ptr<Cat> wp(pCat7);
cout << "pCat7 count: " << wp.use_count() << endl;
if (wp.expired())
{
cout << "wp was expired\n";
}
else
{
cout << "wp was not expired\n";
}
// 手動釋放
pCat7.reset();
if (wp.expired())
{
cout << "wp was expired\n";
}
else
{
cout << "wp was not expired\n";
}
return 0;
}