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. CodeForces - 776C(前缀和+思维)

    链接:CodeForces - 776C 题意:给出数组 a[n] ,问有多少个区间和等于 k^x(x >= 0). 题解:求前缀和,标记每个和的个数.对每一个数都遍历到1e5,记录到答案. # ...

  2. ZOJ 3644 Kitty's Game(数论+DP)

    Description Kitty is a little cat. She is crazy about a game recently. There arenscenes in the game( ...

  3. POJ 1815 Friendship(最大流最小割の字典序割点集)

    Description In modern society, each person has his own friends. Since all the people are very busy, ...

  4. 关于智能指针类型shared_ptr的计数问题

    一.关键 每个shared_ptr所指向的对象都有一个引用计数,它记录了有多少个shared_ptr指向自己 shared_ptr的析构函数:递减它所指向的对象的引用计数,如果引用计数变为0,就会销毁 ...

  5. Thunder团队第三周 - Scrum会议4

    Scrum会议4 小组名称:Thunder 项目名称:i阅app Scrum Master:邹双黛 工作照片: 参会成员: 王航:http://www.cnblogs.com/wangh013/ 李传 ...

  6. 采用c#实现功能1

    看了好多c#的菜鸟教程不如自己开始动手打代码,最终实现了功能一,参考了网上的wordcount代码发现无论是c++还是c#大部分采用的是哈希表的方法实现的,本来还想仅用循环实现遍历句子中的所有字符,即 ...

  7. windows批处理学习(call与start)---02

    参考:https://www.cnblogs.com/Braveliu/p/5078283.html 一.call命令总结 (1)call命令简介 语法: call [ [Drive:] [Path] ...

  8. 【Linux】- Ubutnu UFW防火墙的简单设置

    ufw是一个主机端的iptables类防火墙配置工具,比较容易上手.一般桌面应用使用ufw已经可以满足要求了. 安装方法 sudo apt-get install ufw 使用方法 1.启用: sud ...

  9. 【Spring.Net】- 环境搭建

    参考文章:http://www.cnblogs.com/GoodHelper/archive/2009/10/25/SpringNET_Config.html 一.环境下载及安装 到Spring的官方 ...

  10. 第三部分shell编程3(shell脚本编写1)

    做监控和备份最多 1. shell脚本是什么它是一种脚本语言,并非编程语言可以使用一些逻辑判断.循环等语法可以自定义子函数是系统命令的集合shell脚本可以实现自动化运维,大大增加我们的工作效率 第一 ...