Welcome 微信登录

首页 / 操作系统 / Linux / C++智能指针 unique_ptr

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;
}

unique_ptr 支持管理数组

std::unique_ptr<A[]> ups(new A[10]);
printf("sizeof(ups) = %d ", sizeof(ups));
for (int i = 0; i < 10; i++)
{
ups[i] = i;
printf("ups[i] = %d ", 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 objectpublic: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 constructstatic_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 constructstatic_assert(!is_pointer<_Dx>::value,"unique_ptr constructed with null deleter pointer");}_Myt& operator=(_STD nullptr_t){// assign a null pointerreset();return (*this);}#endif /* defined(_NATIVE_NULLPTR_SUPPORTED) etc. */explicit unique_ptr(pointer _Ptr): _Mybase(_Ptr, _Dx()){// construct with pointerstatic_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 _Rightreset(_Right.release());this->get_deleter() = _STD move(_Right.get_deleter());return (*this);}_Myt& operator=(_Myt&& _Right){// assign by moving _Rightif (this != &_Right){// different, do the movereset(_Right.release());this->get_deleter() = _STD move(_Right.get_deleter());}return (*this);}void swap(_Myt&& _Right){// swap elementsif (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 objectreturn (*this->_Myptr);}pointer operator->() const{// return pointer to class objectreturn (&**this);}pointer get() const{// return pointer to objectreturn (this->_Myptr);}_OPERATOR_BOOL() const{// test for non-null pointerreturn (this->_Myptr != pointer() ? _CONVERTIBLE_TO_TRUE : 0);}pointer release(){// yield ownership of pointerpointer _Ans = this->_Myptr;this->_Myptr = pointer();return (_Ans);}void reset(pointer _Ptr = pointer()){// establish new pointerif (_Ptr != this->_Myptr){// different pointer, delete old and reassign_Delete();this->_Myptr = _Ptr;}}private:void _Delete(){// delete the pointerif (this->_Myptr != pointer())this->get_deleter()(this->_Myptr);}unique_ptr(const _Myt&);// not definedtemplate<class _Ty2,class _Dx2>unique_ptr(const unique_ptr<_Ty2, _Dx2>&);// not defined_Myt& operator=(const _Myt&);// not definedtemplate<class _Ty2,class _Dx2>_Myt& operator=(const unique_ptr<_Ty2, _Dx2>&);// not defined};本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/137996.htm