C 11智慧型指標之unique ptr

2021-09-29 23:56:41 字數 3396 閱讀 1567

針對記憶體洩露的問題,先提下c語言中該怎麼辦?有幾點建議:

(1)乙個unique_ptr持有所指物件的獨有權,即同一時刻只能有乙個unique_ptr指向同乙個物件。當這個unique_ptr被銷毀時,指向的物件也跟著被銷毀。

(2)擁有指標本身的生命週期:從unique_ptr指標建立時開始,直到離開作用域。離開作用域時,若其指向物件,則將其所指物件銷毀。

(3)使用c++11 智慧型指標需要包含下面的標頭檔案

#include
常見方式有:

std::unique_ptru_ptr;  // 指向int型別的unique_ptr,只不過為空

u_ptr = std::unique_ptr(new int(20));

//unique_ptrstd::unique_ptrup1(new string("hello"));

std::unique_ptrup2(new int[10]); //陣列需要特別注意

可以指向乙個new出來的物件。

上面的兩種方式結合,如下:

std::unique_ptrup;//宣告空的unique_ptr

int *p = new int(1111);

up.reset(p);//reset先釋放up原先指向的記憶體,再令up指向新的物件,p為內建指標

通常來說,在銷毀物件的時候,都是使用delete來銷毀,但是也可以使用指定的方式進行銷毀。

舉個簡單的例子,假如你開啟了乙個連線,獲取到了乙個檔案描述符,現在你想通過unique_ptr來管理,希望在不需要的時候,能夠借助unique_ptr幫忙關閉它。

#include #include #include void myclose(int *fd)

int main()

); return 0;

}

它的用法如下:

std::unique_ptrup(t,d);

std::unique_ptrup(d);//空的unique_ptr

含義分別如下:

例子中使用了decltype(myclose)*用於獲取myclose函式的型別,*表明它是乙個指標型別,即函式指標,它傳入引數是int*。你也可以使用注釋中的方式。

即便後面執行出現異常時,這個socket連線也能夠正確關閉。

後面我們也可以看到,與shared_ptr不同,unique_ptr在編譯時繫結刪除器,避免了執行時開銷。

一般來說,unique_ptr被銷毀時(如離開作用域),物件也就被自動釋放了,也可以通過其他方式顯示釋放物件。如:

up = nullptr; // 置為空,釋放up指向的物件

up.release(); // 放棄控制權,返回裸指標,並將up置為空

up.reset(); // 釋放up指向的物件

可以看到release和reset的區別在於,前者會釋放控制權,返回裸指標,你還可以繼續使用;而後者直接釋放了指向物件。

需要特別注意的是,由於unique_ptr「獨有」的特點,它不允許進行普通的拷貝或賦值,例如:

std::unique_ptrup0;

std::unique_ptrup1(new int(1111));

up0 = up1; //錯誤,不支援賦值

std::unique_ptrup2(up1); //錯誤,不支援拷貝

總之記住,既然unique_ptr是獨享物件,那麼任何可能被共享的操作都是不允許的,但是可以移動。

雖然unique_ptr獨享物件,但是也可以移動,即轉移控制權。如:

std::unique_ptrup1(new int(42));

std::unique_ptrup2(up1.release());

up2接受up1 release之後的指標,或者:

std::unique_ptrup1(new int(42));

std::unique_ptrup2;

up2.reset(up1.release());

再或者使用move:

std::unique_ptrup1(new int(42));

std::unique_ptrup2(std::move(up1));

如果函式以unique_ptr作為引數呢?如果像下面這樣直接把unique_ptr作為引數肯定就報錯了,因為它不允許被複製:

#include #include void test(std::unique_ptrp)

int main()

上面的**編譯將直接報錯。

當然我們可以向函式中傳遞普通指標,使用get函式就可以獲取裸指標,如:

#include #include void test(int *p)

int main()

或者使用引用作為引數:

#include #include void test(std::unique_ptr&p)

int main()

如果外部不再需要使用了,完全可以轉移,將物件交給你呼叫的函式管理,這裡可以使用move函式或release函式

#include #include void test(std::unique_ptrp)

int main()

unique_ptr可以作為引數返回:

#include #include std::unique_ptrtest(int i)

int main()

你還可以把unique_ptr轉換為shared_ptr使用,如注釋行所示。

為什麼要優先使用unique_ptr,原因如下:

第一點相信很好理解,自動管理,不需要時即釋放,甚至可以防止下面這樣的情況:

int * p = new int(1111);

/*do something*/

delete p;

如果在do something的時候,出現了異常,退出了,那delete就永遠沒有執行的機會,就會造成記憶體洩露,而如果使用unique_ptr就不會有這樣的困擾了。

第二點為何這麼說?因為相比於shared_ptr,它的開銷更小,甚至可以說和裸指標相當,它不需要維護引用計數的原子操作等等。

所以說,如果盡可能優先選用unique_ptr。

C 11之智慧型指標

c 98提供了了智慧型指標auto ptr,但c 11已將其摒棄,並提供了unique ptr和shared ptr。這三種智慧型指標模板都定義了類似指標的物件,可以將new獲得的位址賦給這種物件。當智慧型指標過期時,這些記憶體將自動被釋放。其基本用法如下 include include inclu...

c 11之智慧型指標

由於在c 中我們可以動態分配記憶體,但有時候我們會忘記用 delete或free釋放記憶體,就會導致記憶體洩露。所以c 11提供了智慧型指標這種東西 本文參考了知乎某知乎友的 比如下面這兩種情況 1 記憶體洩漏 str1所指的資源沒有被釋放 2 多重釋放,引起程式崩潰 可能平時都寫在乙個檔案不會忘記...

C 11智慧型指標

本文介紹c 的四種智慧型指標,其中後三種是c 11新增加的,auto ptr已被棄用。要編譯c 11,需要安裝g 4.8 sudo add apt repository ppa ubuntu toolchain r test sudo apt get update sudo apt get inst...