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\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 : );
} 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
};

C++智能指针 unique_ptr的更多相关文章

  1. c/c++ 智能指针 unique_ptr 使用

    智能指针 unique_ptr 使用 和shared_ptr不同,可以有多个shared_ptr指向同一个内存,只能有1个unique_ptr指向某个内存.因此unique_ptr不支持普通的拷贝和赋 ...

  2. c++11 智能指针 unique_ptr、shared_ptr与weak_ptr

    c++11 智能指针 unique_ptr.shared_ptr与weak_ptr C++11中有unique_ptr.shared_ptr与weak_ptr等智能指针(smart pointer), ...

  3. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

  4. C++11 智能指针unique_ptr使用 -- 以排序二叉树为例

    用智能指针可以简化内存管理.以树为例,如果用普通指针,通常是在插入新节点时用new,在析构函数中调用delete:但有了unique_ptr类型的智能指针,就不需要在析构函数中delete了,因为当u ...

  5. C++——智能指针unique_ptr的实现

    起初,我最直观的设计想法,直接设计一个类:包含全部要素(对象,指针计数).然后提供出去. class CPoint { public: CPoint(, ) : x(xVal), y(yVal) {} ...

  6. 智能指针unique_ptr

    转自:https://www.cnblogs.com/DswCnblog/p/5628195.html 成员函数 (1) get 获得内部对象的指针, 由于已经重载了()方法, 因此和直接使用对象是一 ...

  7. 智能指针 unique_ptr

    unique_ptr 不共享它的指针.它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法. 1.不能进行复制构造和赋值操作(unique ...

  8. 智能指针unique_ptr记录

    unique_ptr 对对象独有管理,无法复制,共享,值传递,可以使用move语义来转移控制权. std::default_delete<int> d; std::unique_ptr&l ...

  9. 第20课 unique_ptr独占型智能指针

    一. unique_ptr的基本用法 (一)初始化方式 1. 直接初始化:unique<T> myPtr(new T);  //ok.但不能通过隐式转换来构造,如unique<T&g ...

随机推荐

  1. 一个简单的Spring的AOP例子

    目标对象的接口:IStudent.java  1  /**  2  *  3   */  4  package  com.dragon.study; 5   6  /**  7  *  @author ...

  2. 2.安装hdfs yarn

    下载hadoop压缩包设置hadoop环境变量设置hdfs环境变量设置yarn环境变量设置mapreduce环境变量修改hadoop配置设置core-site.xml设置hdfs-site.xml设置 ...

  3. Word Ladder Problem (DFS + BFS)

    Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest t ...

  4. Python 字符串与基本语句

    Python特点 python中没有变量的声明 语句结束后没有分号 严格要求缩进 支持很长很长的大数运算(直接在Idle中输入即可) 用"#"来注释 BIF:Bulit-in fu ...

  5. C#及时释放代码

    using语句,定义一个范围,在范围结束时释放对象. 场景: 当在某个代码段中使用了类的实例,而希望无论因为什么原因,只要离开了这个代码段就自动调用这个类实例的Dispose. 要达到这样的目的,用t ...

  6. lintcode-167-链表求和

    167-链表求和 你有两个用链表代表的整数,其中每个节点包含一个数字.数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头.写出一个函数将两个整数相加,用链表形式返回和. 样例 给出两个链 ...

  7. python模拟SQL语句操作文件

    1.需求 在文本界面输入SQL语句,查询相应的数据,例如输入下面的语句 print(''' 支持大小写的SQL语句查询,大写或者小写都可以 1. select * from db1.emp 2. se ...

  8. TCP系列32—窗口管理&流控—6、TCP zero windows和persist timer

    一.简介 我们之前介绍过,TCP报文中的window size表示发出这个报文的一端准备多少bytes的数据,当TCP的一端一直接收数据,但是应用层没有及时读取的话,数据一直在TCP模块中缓存,最终受 ...

  9. 华为oj----iNOC产品部-杨辉三角的变形 .

    此题提供三种方法,第一种,一开始就能想到的,设置一个足够大的数组存储生成的杨辉三角,然后进行判断就行,此方法参见:华为oj iNOC产品部-杨辉三角的变形 另一种方法是采用递归: 三角形的每行的个数为 ...

  10. array_intersect_assoc 与array_intersect区别

    1.array_intersect_assoc — 带索引检查计算数组的交集 说明 array array_intersect_assoc ( array $array1 , array $array ...