auto_ptr與unique_ptr

auto_ptr與unique_ptr

auto_ptr是用於C++11之前的智能指針。由於 auto_ptr 基於排他所有權模式:兩個指針不能指向同一個資源,複製或賦值都會改變資源的所有權。auto_ptr 主要有兩大問題:

o 複製和賦值會改變資源的所有權,不符合人的直覺。
o 在 STL 容器中無法使用auto_ptr ,因爲容器內的元素必需支持可複製(copy constructable)和可賦值(assignable)。

unique_ptr特性
o 擁有它所指向的對象
o 無法進行復制構造,也無法進行復制賦值操作
o 保存指向某個對象的指針,當它本身離開作用域時會自動釋放它指向的對象。

unique_ptr可以:
o 爲動態申請的內存提供異常安全
o 將動態申請內存的所有權傳遞給某個函數
o 從某個函數返回動態申請內存的所有權
o 在容器中保存指針
unique_ptr十分依賴於右值引用和移動語義。

在C++11中已經放棄auto_ptr轉而推薦使用unique_ptr和shared_ptr。unique跟auto_ptr類似同樣只能有一個智能指針對象指向某塊內存.但它還有些其他特性。unique_ptr對auto_ptr的改進如下:

1, auto_ptr支持拷貝構造與賦值操作,但unique_ptr不直接支持
auto_ptr通過拷貝構造或者operator=賦值後,對象所有權轉移到新的auto_ptr中去了,原來的auto_ptr對象就不再有效,這點不符合人的直覺。unique_ptr則直接禁止了拷貝構造與賦值操作。
auto_ptr<int> ap(new int(10));
auto_ptr<int> one (ap) ; // ok
auto_ptr<int> two = one; //ok

unique_ptr<int> ap(new int(10));
unique_ptr<int> one (ap) ; // 會出錯
unique_ptr<int> two = one; //會出錯

2,unique_ptr可以用在函數返回值中
unique_ptr像上面這樣一般意義上的複製構造和賦值或出錯,但在函數中作爲返回值卻可以用.
unique_ptr<int> GetVal( ){
unique_ptr<int> up(new int(10 );
return up;
}
unique_ptr<int> uPtr = GetVal(); //ok

實際上上面的的操作有點類似於如下操作
unique_ptr<int> up(new int(10);
unique_ptr<int> uPtr2 = std:move( up) ; //這裏是顯式的所有權轉移. 把up所指的內存轉給uPtr2了,而up不再擁有該內存

3,unique_ptr可做爲容器元素
我們知道auto_ptr不可做爲容器元素,會導致編譯錯誤。雖然unique_ptr同樣不能直接做爲容器元素,但可以通過move語意實現。
unique_ptr<int> sp(new int(88) );
vector<unique_ptr<int> > vec;
vec.push_back(std::move(sp));
// vec.push_back( sp ); error:
// cout << *sp << endl;
std::move讓調用者明確知道拷貝構造、賦值後會導致之前的unique_ptr失效。

 

 

 

#include <memory>
#include <vector>
#include <cassert>
using namespace std;

unique_ptr<int> GetVal( ){
 unique_ptr<int> up(new int(10));
    return up;
}

int main()
{
    // auto_ptr支持拷貝構造與賦值,拷貝構造或賦值後對象所有權轉移
 auto_ptr<int> aPtr(new int(10));
    auto_ptr<int> a1 (aPtr);  // call copy constuctor, OK
    assert(aPtr.get() == nullptr && a1.get() != nullptr);

    auto_ptr<int> a2(NULL);
    a2 = a1;        // call operator=, OK
    assert(a1.get() == nullptr && a2.get() != nullptr);

    // unique_ptr不支持直接拷貝構造與賦值
    unique_ptr<int> uPtr(new int(10));
    // unique_ptr<int> u1 (uPtr);       // call copy constructor, error 
    // Error: Call to implicitly-deleted copy constructor of 'unique_ptr<int>'

    // unique_ptr<int> u2 = nullptr;
    // u2 = uPtr;               // call operator=, error
    // Error: Overload resolution selected implicitly-deleted copy assignment operator

    // unique_ptr支持move語意的拷貝構造
    unique_ptr<int> u1(std::move(uPtr));
    assert(uPtr == nullptr && u1 != nullptr);

    // unique_ptr支持move語意的賦值
    unique_ptr<int> u2 = std::move(u1) ; // 把u1所指的內存轉給u2了,而u1不再擁有該內存
    assert(u1 == nullptr && u2 != nullptr);

    // unique_ptr通過move語意可放入STL容器
    unique_ptr<int> sp(new int(100));
    vector<unique_ptr<int>> vec;
    vec.push_back(std::move(sp));

    // vec.push_back(sp);
    // Error: Call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<int, std::__1::default_delete<int> >'

    assert(sp == nullptr);
    // cout << *sp << endl;  // crash at this point, sp is nullptr now

    unique_ptr<int> g_uPtr = GetVal();   //ok
}

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