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
}