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));
A* p = up2.release();
delete p;
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)
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());
雖然 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;
}
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]);
}
重載一個 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
};