unique_ptr的使用
分配內存
與shared_ptr不同,unique_ptr沒有定義類似make_shared的操作,因此只可以使用new來分配內存,並且由於unique_ptr不可拷貝和賦值,初始化unique_ptr必須使用直接初始化的方式。
unique_ptr<int> up1(new int()); //okay,直接初始化
unique_ptr<int> up2 = new int(); //error! 構造函數是explicit
unique_ptr<int> up3(up1); //error! 不允許拷貝
不可 拷貝和賦值
與shared_ptr不同,unique_ptr擁有它所指向的對象,在某一時刻,只能有一個unique_ptr指向特定的對象。當unique_ptr被銷燬時,它所指向的對象也會被銷燬。因此不允許多個unique_ptr指向同一個對象,所以不允許拷貝與賦值。
unique_ptr的操作
-
unique_ptr<T> up
空的unique_ptr,可以指向類型爲T的對象,默認使用delete來釋放內存 -
unique_ptr<T,D> up(d)
空的unique_ptr同上,接受一個D類型的刪除器d,使用刪除器d來釋放內存 -
up = nullptr
釋放up指向的對象,將up置爲空 -
up.release()
up放棄對它所指對象的控制權,並返回保存的指針,將up置爲空,不會釋放內存 -
up.reset(…)
參數可以爲 空、內置指針,先將up所指對象釋放,然後重置up的值.
傳遞unique_ptr參數和返回unique_ptr
前面說了unique_ptr不可拷貝和賦值,那要怎樣傳遞unique_ptr參數和返回unique_ptr呢?
事實上不能拷貝unique_ptr的規則有一個例外:我們可以拷貝或賦值一個將要被銷燬的unique_ptr (C++ Primer 5th p418)
//從函數返回一個unique_ptr
unique_ptr func1(int a)
{
return unique_ptr<int> (new int(a));
}
//返回一個局部對象的拷貝
unique_ptr func2(int a)
{
unique_ptr<int> up(new int(a));
return up;
}
傳unique_ptr參數可以使用引用避免所有權的轉移,或者暫時的移交所有權
void func1(unique_ptr<int> &up){
cout<<*up<<endl;
}
unique_ptr<int> func2(unique_ptr<int> up){
cout<<*up<<endl;
return up;
}
//使用up作爲參數
unique_ptr<int> up(new int(10));
//傳引用,不拷貝,不涉及所有權的轉移
func1(up);
//暫時轉移所有權,函數結束時返回拷貝,重新收回所有權
up = func2(unique_ptr<int> (up.release()));
//如果不用up重新接受func2的返回值,這塊內存就泄漏了
向unique_ptr傳遞刪除器
類似shared_ptr,用unique_ptr管理非new對象、沒有析構函數的類時,需要向unique_ptr傳遞一個刪除器。不同的是,unique_ptr管理刪除器的方式,我們必須在尖括號中unique_ptr指向類型後面提供刪除器的類型,在創建或reset一個這種unique_ptr對象時,必須提供一個相同類型的可調用對象(刪除器),這個刪除器接受一個T*參數。
unique_ptr的陷阱
不要與裸指針混用
unique_ptr不允許兩個獨佔指針指向同一個對象,在沒有裸指針的情況下,我們只能用release獲取內存的地址,同時放棄對對象的所有權,這樣就有效避免了多個獨佔指針同時指向一個對象。
而使用裸指針就很容器打破這一點
int *x(new int());
unique_ptr<int> up1,up2;
//會使up1 up2指向同一個內存
up1.reset(x);
up2.reset(x);
要避免寫這樣的程序
記得使用u.release()的返回值
在調用u.release()時是不會釋放u所指的內存的,這時返回值就是對這塊內存的唯一索引,如果沒有使用這個返回值釋放內存或是保存起來,這塊內存就泄漏了