unique_ptr的使用和陷阱

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的操作

  1. unique_ptr<T> up 
    空的unique_ptr,可以指向類型爲T的對象,默認使用delete來釋放內存

  2. unique_ptr<T,D> up(d) 
    空的unique_ptr同上,接受一個D類型的刪除器d,使用刪除器d來釋放內存

  3. up = nullptr 
    釋放up指向的對象,將up置爲空

  4. up.release() 
    up放棄對它所指對象的控制權,並返回保存的指針,將up置爲空,不會釋放內存

  5. 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所指的內存的,這時返回值就是對這塊內存的唯一索引,如果沒有使用這個返回值釋放內存或是保存起來,這塊內存就泄漏了

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