unique_ptr 獨佔所指向的對象, 同一時刻只能有一個 unique_ptr 指向給定對象(經過禁止拷貝語義, 只有移動語義來實現), 定義於 memory (非memory.h)中, 命名空間爲 std.
標準庫早期版本中定義了 auto_ptr, 它具備 unique_ptr 的部分特徵, 但不是所有, 例如, 不能在容器中保存 auto_ptr, 也不能從函數中返回 auto_ptr.
基於這些緣由, 應該儘可能使用 unique_ptr, 而不是 auto_ptr, 使用 unique_ptr 替換 auto_ptr. 數組
基本用法:函數
std::unique_ptr<A> up1;
up1.reset(new A(3));
std::unique_ptr<A> up2(new A(4));this
A* p = up2.release();
delete p;spa
std::unique_ptr<A> up3(new A(11));
std::unique_ptr<A> up4 = std::move(up3);
up4 = nullptr;//顯式銷燬所指對象,同時智能指針變爲空指針。與u_s2.reset()等價指針
(1) get 得到內部對象的指針, 因爲已經重載了()方法, 所以和直接使用對象是同樣的.如 unique_ptr<int> sp(new int(1)); sp 與 sp.get()是等價的
(2) release 放棄內部對象的全部權,將內部指針置爲空, 返回所內部對象的指針, 此指針須要手動釋放
(3) reset 銷燬內部對象並接受新的對象的全部權(若是使用缺省參數的話,也就是沒有任何對象的全部權, 此時僅將內部對象釋放, 並置爲空)
(4) swap 交換兩個 shared_ptr 對象(即交換所擁有的對象)
std::move(up) 全部權轉移(經過移動語義), up全部權轉移後,變成「空指針」 (up 的定義爲 std::unique_ptr<Ty> up)code
unique_ptr 不支持拷貝和賦值.
std::unique_ptr<A> up1(new A(5));
std::unique_ptr<A> up2(up1); // 錯誤, unique_ptr 不支持拷貝
std::unique_ptr<A> up2 = up1; // 錯誤, unique_ptr 不支持賦值對象
雖然 unique_ptr 不支持拷貝和賦值, 可是咱們能夠調用 release 或 reset 將指針的全部權從一個(非 const) unique_ptr 轉移到另外一個.
std::unique_ptr<int> up1(new int(1));
std::unique_ptr<int> up2(up1.release());blog
雖然 unique_ptr 不支持拷貝, 可是能夠從函數中返回, 甚至返回局部對象. 以下面的代碼, 編譯器知道要返回的對象即將被銷燬, 所以執行一種特殊的"拷貝":
template <class Ty>
std::unique_ptr<Ty> Clone(const Ty& obj)
{
return std::unique_ptr<Ty>(new Ty(obj));
}
template <class Ty>
std::unique_ptr<Ty> Clone(const Ty& obj)
{
std::unique_ptr<Ty> temp = std::unique_ptr<Ty>(new Ty(obj));
return temp;
}ip
std::unique_ptr<A[]> ups(new A[10]);
printf("sizeof(ups) = %d\n", sizeof(ups));
for (int i = 0; i < 10; i++)
{
ups[i] = i;
printf("ups[i] = %d\n", ups[i]);
}ci
重載一個 unique_ptr 的刪除器會影響到 unique_ptr 類型以及如何構造該類的對象, 必須在尖括號中指定刪除器類型. 而後在建立或 reset 時提供刪除器對象.
unique_ptr<T, D> up;
可使用 decltype 來指明函數指針的類型.
class CConnnect { void Disconnect() { PRINT_FUN(); } }; void Deleter(CConnnect* obj) { obj->Disconnect(); // 作其它釋放或斷開鏈接等工做 delete obj; // 刪除對象指針 } std::unique_ptr<CConnnect, decltype(Deleter)*> up(new CConnnect, Deleter);
另外一種用法:
class Deleter { public: void operator() (CConnnect* obj) { PRINT_FUN(); delete obj; } }; std::unique_ptr<CConnnect, Deleter> up1(new CConnnect); std::unique_ptr<CConnnect, Deleter> up2(new CConnnect, up1.get_deleter());
VC中的源碼實現
template<class _Ty, class _Dx> // = default_delete<_Ty> class unique_ptr : public _Unique_ptr_base<_Ty, _Dx, tr1::is_empty<_Dx>::value || tr1::is_same<default_delete<_Ty>, _Dx>::value> { // non-copyable pointer to an object public: typedef unique_ptr<_Ty, _Dx> _Myt; typedef _Unique_ptr_base<_Ty, _Dx, tr1::is_empty<_Dx>::value || tr1::is_same<default_delete<_Ty>, _Dx>::value> _Mybase; typedef typename _Mybase::pointer pointer; typedef _Ty element_type; typedef _Dx deleter_type; unique_ptr() : _Mybase(pointer(), _Dx()) { // default construct static_assert(!is_pointer<_Dx>::value, "unique_ptr constructed with null deleter pointer"); } #if defined(_NATIVE_NULLPTR_SUPPORTED) \ && !defined(_DO_NOT_USE_NULLPTR_IN_STL) unique_ptr(_STD nullptr_t) : _Mybase(pointer(), _Dx()) { // null pointer construct static_assert(!is_pointer<_Dx>::value, "unique_ptr constructed with null deleter pointer"); } _Myt& operator=(_STD nullptr_t) { // assign a null pointer reset(); return (*this); } #endif /* defined(_NATIVE_NULLPTR_SUPPORTED) etc. */ explicit unique_ptr(pointer _Ptr) : _Mybase(_Ptr, _Dx()) { // construct with pointer static_assert(!is_pointer<_Dx>::value, "unique_ptr constructed with null deleter pointer"); } unique_ptr(pointer _Ptr, typename _If<tr1::is_reference<_Dx>::value, _Dx, const typename tr1::remove_reference<_Dx>::type&>::_Type _Dt) : _Mybase(_Ptr, _Dt) { // construct with pointer and (maybe const) deleter& } unique_ptr(pointer _Ptr, typename tr1::remove_reference<_Dx>::type&& _Dt) : _Mybase(_Ptr, _STD move(_Dt)) { // construct by moving deleter // static_assert(!tr1::is_reference<_Dx>::value, // "unique_ptr constructed with reference to rvalue deleter"); } unique_ptr(unique_ptr&& _Right) : _Mybase(_Right.release(), _STD forward<_Dx>(_Right.get_deleter())) { // construct by moving _Right } template<class _Ty2, class _Dx2> unique_ptr(unique_ptr<_Ty2, _Dx2>&& _Right) : _Mybase(_Right.release(), _STD forward<_Dx2>(_Right.get_deleter())) { // construct by moving _Right } template<class _Ty2, class _Dx2> _Myt& operator=(unique_ptr<_Ty2, _Dx2>&& _Right) { // assign by moving _Right reset(_Right.release()); this->get_deleter() = _STD move(_Right.get_deleter()); return (*this); } _Myt& operator=(_Myt&& _Right) { // assign by moving _Right if (this != &_Right) { // different, do the move reset(_Right.release()); this->get_deleter() = _STD move(_Right.get_deleter()); } return (*this); } void swap(_Myt&& _Right) { // swap elements if (this != &_Right) { // different, do the swap _Swap_adl(this->_Myptr, _Right._Myptr); _Swap_adl(this->get_deleter(), _Right.get_deleter()); } } void swap(_Myt& _Right) { // swap elements _Swap_adl(this->_Myptr, _Right._Myptr); _Swap_adl(this->get_deleter(), _Right.get_deleter()); } ~unique_ptr() { // destroy the object _Delete(); } typename tr1::add_reference<_Ty>::type operator*() const { // return reference to object return (*this->_Myptr); } pointer operator->() const { // return pointer to class object return (&**this); } pointer get() const { // return pointer to object return (this->_Myptr); } _OPERATOR_BOOL() const { // test for non-null pointer return (this->_Myptr != pointer() ? _CONVERTIBLE_TO_TRUE : 0); } pointer release() { // yield ownership of pointer pointer _Ans = this->_Myptr; this->_Myptr = pointer(); return (_Ans); } void reset(pointer _Ptr = pointer()) { // establish new pointer if (_Ptr != this->_Myptr) { // different pointer, delete old and reassign _Delete(); this->_Myptr = _Ptr; } } private: void _Delete() { // delete the pointer if (this->_Myptr != pointer()) this->get_deleter()(this->_Myptr); } unique_ptr(const _Myt&); // not defined template<class _Ty2, class _Dx2> unique_ptr(const unique_ptr<_Ty2, _Dx2>&); // not defined _Myt& operator=(const _Myt&); // not defined template<class _Ty2, class _Dx2> _Myt& operator=(const unique_ptr<_Ty2, _Dx2>&); // not defined };