C++11 unique_ptr用法
unique_ptr?不共享它的指針。它無法復制到其他?unique_ptr,無法通過值傳遞到函數,也無法用于需要副本的任何標準模板庫 (STL) 算法。只能移動unique_ptr。這意味著,內存資源所有權將轉移到另一?unique_ptr,并且原始?unique_ptr?不再擁有此資源。我們建議你將對象限制為由一個所有者所有,因為多個所有權會使程序邏輯變得復雜。因此,當需要智能指針用于純 C++ 對象時,可使用?unique_ptr,而當構造?unique_ptr?時,可使用make_unique?Helper 函數。
std::unique_ptr實現了獨享所有權的語義。一個非空的std::unique_ptr總是擁有它所指向的資源。轉移一個std::unique_ptr將會把所有權也從源指針轉移給目標指針(源指針被置空)。拷貝一個std::unique_ptr將不被允許,因為如果你拷貝一個std::unique_ptr,那么拷貝結束后,這兩個std::unique_ptr都會指向相同的資源,它們都認為自己擁有這塊資源(所以都會企圖釋放)。因此std::unique_ptr是一個僅能移動(move_only)的類型。當指針析構時,它所擁有的資源也被銷毀。默認情況下,資源的析構是伴隨著調用std::unique_ptr內部的原始指針的delete操作的。
下圖演示了兩個?unique_ptr?實例之間的所有權轉換。
1、如何創建unique_ptr
unique_ptr不像shared_ptr一樣擁有標準庫函數make_shared來創建一個shared_ptr實例。要想創建一個unique_ptr,我們需要將一個new 操作符返回的指針傳遞給unique_ptr的構造函數。
示例:
int main() {// 創建一個unique_ptr實例unique_ptr<int> pInt(new int(5));cout << *pInt; }2、無法進行復制構造和賦值操作
unique_ptr沒有copy構造函數,不支持普通的拷貝和賦值操作。
int main() {// 創建一個unique_ptr實例unique_ptr<int> pInt(new int(5));unique_ptr<int> pInt2(pInt); // 報錯unique_ptr<int> pInt3 = pInt; // 報錯 }3、可以進行移動構造和移動賦值操作
unique_ptr雖然沒有支持普通的拷貝和賦值操作,但卻提供了一種移動機制來將指針的所有權從一個unique_ptr轉移給另一個unique_ptr。如果需要轉移所有權,可以使用std::move()函數。
示例:
int main() {unique_ptr<int> pInt(new int(5));unique_ptr<int> pInt2 = std::move(pInt); // 轉移所有權//cout << *pInt << endl; // 出錯,pInt為空cout << *pInt2 << endl;unique_ptr<int> pInt3(std::move(pInt2)); }4、可以返回unique_ptr
unique_ptr不支持拷貝操作,但卻有一個例外:可以從函數中返回一個unique_ptr。
示例:
unique_ptr<int> clone(int p) {unique_ptr<int> pInt(new int(p));return pInt; // 返回unique_ptr }int main() {int p = 5;unique_ptr<int> ret = clone(p);cout << *ret << endl; } 使用舉例:{//創建一個指向int的空指針std::unique_ptr<int> fPtr1;std::unique_ptr<int> fPtr2(new int(4));auto fPtr3 = std::make_unique<int>();//fPtr2釋放指向對象的所有權,并且被置為nullptrstd::cout << "fPtr2 release before:" << fPtr2.get() << std::endl;int *pF = fPtr2.release();std::cout << "fPtr2 release before:" << fPtr2.get() << " and pF value:" << *pF << std::endl;//所有權轉移,轉移后fPtr3變為空指針std::cout << "move before fPtr1 address:" << fPtr1.get() << " fPtr3 address:" << fPtr3.get() << std::endl;fPtr1 = std::move(fPtr3);std::cout << "move after fPtr1 address:" << fPtr1.get() << " fPtr3 address:" << fPtr3.get() << std::endl;std::cout << "move before fPtr1 address:" << fPtr1.get() << std::endl;fPtr1.reset();std::cout << "move after fPtr1 address:" << fPtr1.get() << std::endl;}輸出:fPtr2 release before:00EFB120fPtr2 release before:00000000 and pF value:4move before fPtr1 address:00000000 fPtr3 address:00EFEC60move after fPtr1 address:00EFEC60 fPtr3 address:00000000move before fPtr1 address:00EFEC60move after fPtr1 address:00000000?
unique_ptr使用場景
1、為動態申請的資源提供異常安全保證
我們先來看看下面這一段代碼:
void Func() {int *p = new int(5);// ...(可能會拋出異常)delete p; }這是我們傳統的寫法:當我們動態申請內存后,有可能我們接下來的代碼由于拋出異常或者提前退出(if語句)而沒有執行delete操作。
解決的方法是使用unique_ptr來管理動態內存,只要unique_ptr指針創建成功,其析構函數都會被調用。確保動態資源被釋放。
void Func() {unique_ptr<int> p(new int(5));// ...(可能會拋出異常) }2、返回函數內動態申請資源的所有權
unique_ptr<int> Func(int p) {unique_ptr<int> pInt(new int(p));return pInt; // 返回unique_ptr }int main() {int p = 5;unique_ptr<int> ret = Func(p);cout << *ret << endl;// 函數結束后,自動釋放資源 }3、在容器中保存指針
int main() {vector<unique_ptr<int>> vec;unique_ptr<int> p(new int(5));vec.push_back(std::move(p)); // 使用移動語義 }4、管理動態數組
標準庫提供了一個可以管理動態數組的unique_ptr版本。
int main() {unique_ptr<int[]> p(new int[5] {1, 2, 3, 4, 5});p[0] = 0; // 重載了operator[] }5、作為auto_ptr的替代品
創建與釋放舉例
#include <iostream> #include <memory> #include <stdlib.h>struct Foo {Foo() { std::cout << "Foo::Foo\n"; }~Foo() { std::cout << "Foo::~Foo\n"; }void bar() { std::cout << "Foo::bar\n"; } };void f(const Foo &) {std::cout << "f(const Foo&)\n"; }struct D {void operator()(Foo* foo){std::cout << "D operator()" << std::endl;delete foo;} };void TestAutoDestroy() {//1. 普通的new對象.std::cout << "TestDestroy...................." << std::endl;{std::unique_ptr<Foo> p1(new Foo);}//2. 普通的new[]對象.{std::unique_ptr<Foo[]> p2(new Foo[4]);}//3. 自定義的deleter.{std::unique_ptr<Foo, D> p3(new Foo);} }void TestOwner() {std::cout << "TestOwner...................." << std::endl;//1. new object.std::unique_ptr<Foo> p1(new Foo); // p1 owns Fooif (p1) p1->bar();{std::unique_ptr<Foo> p2(std::move(p1)); // now p2 owns Foof(*p2);p1 = std::move(p2); // ownership returns to p1p2->bar();std::cout << "destroying p2...\n";}p1->bar(); }void TestArrayOwner() {std::cout << "TestArrayOwner...................." << std::endl;//1. new[] object.std::unique_ptr<Foo[]> p1(new Foo[4]); // p1 owns Fooif (p1) p1[0].bar();{std::unique_ptr<Foo[]> p2(std::move(p1)); // now p2 owns Foof(p2[0]);p1 = std::move(p2); // ownership returns to p1p2[0].bar();std::cout << "destroying p2...\n";}p1[0].bar(); }int main() {TestAutoDestroy();TestOwner();TestArrayOwner(); }輸出: TestDestroy.................... Foo::Foo Foo::~Foo Foo::Foo Foo::Foo Foo::Foo Foo::Foo Foo::~Foo Foo::~Foo Foo::~Foo Foo::~Foo Foo::Foo D?operator() Foo::~Foo TestOwner.................... Foo::Foo Foo::bar f(const?Foo&) Foo::bar destroying?p2... Foo::bar Foo::~Foo TestArrayOwner.................... Foo::Foo Foo::Foo Foo::Foo Foo::Foo Foo::bar f(const?Foo&) Foo::bar destroying?p2... Foo::bar Foo::~Foo Foo::~Foo Foo::~Foo Foo::~Foo ??
??上一篇:?C++ 11 創建和使用 shared_ptr
??下一篇:?C++ 11 創建和使用共享 weak_ptr
?
總結
以上是生活随笔為你收集整理的C++11 unique_ptr用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简谈C/C++学习路线
- 下一篇: C++ 11 创建和使用共享 weak_