C++智能指针 unique_ptr
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的更多相关文章
- c/c++ 智能指针 unique_ptr 使用
智能指针 unique_ptr 使用 和shared_ptr不同,可以有多个shared_ptr指向同一个内存,只能有1个unique_ptr指向某个内存.因此unique_ptr不支持普通的拷贝和赋 ...
- 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), ...
- 智能指针unique_ptr的用法
unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...
- C++11 智能指针unique_ptr使用 -- 以排序二叉树为例
用智能指针可以简化内存管理.以树为例,如果用普通指针,通常是在插入新节点时用new,在析构函数中调用delete:但有了unique_ptr类型的智能指针,就不需要在析构函数中delete了,因为当u ...
- C++——智能指针unique_ptr的实现
起初,我最直观的设计想法,直接设计一个类:包含全部要素(对象,指针计数).然后提供出去. class CPoint { public: CPoint(, ) : x(xVal), y(yVal) {} ...
- 智能指针unique_ptr
转自:https://www.cnblogs.com/DswCnblog/p/5628195.html 成员函数 (1) get 获得内部对象的指针, 由于已经重载了()方法, 因此和直接使用对象是一 ...
- 智能指针 unique_ptr
unique_ptr 不共享它的指针.它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法. 1.不能进行复制构造和赋值操作(unique ...
- 智能指针unique_ptr记录
unique_ptr 对对象独有管理,无法复制,共享,值传递,可以使用move语义来转移控制权. std::default_delete<int> d; std::unique_ptr&l ...
- 第20课 unique_ptr独占型智能指针
一. unique_ptr的基本用法 (一)初始化方式 1. 直接初始化:unique<T> myPtr(new T); //ok.但不能通过隐式转换来构造,如unique<T&g ...
随机推荐
- python3爬虫-快速入门-爬取图片和标题
直接上代码,先来个爬取豆瓣图片的,大致思路就是发送请求-得到响应数据-储存数据,原理的话可以先看看这个 https://www.cnblogs.com/sss4/p/7809821.html impo ...
- 【Linux 运维】查看网络连接状态信息之netstat和ss命令详解
一.netstat 常用命令详解 通过man netstat可以查看netstat的帮助信息: netstat 命令:用于显示各种网络相关信息,如网络连接,路由表,接口状态,无效连接,组播成员 等等. ...
- 福大软工1816:Alpha(4/10)
Alpha 冲刺 (4/10) 队名:Jarvis For Chat 组长博客链接 本次作业链接 团队部分 工作情况汇报 张扬(组长) 过去两天完成了哪些任务: 文字/口头描述: 1.将中文分词.词频 ...
- Spring Boot(四)@EnableXXX注解分析
在学习使用springboot过程中,我们经常碰到以@Enable开头的注解,其实早在Spring3中就已经出现了类似注解,比如@EnableTransactionManagement.@ Enabl ...
- error : Web 项目“RealEstate.Web”的 URL“http://localhost:20000”已配置为将 IIS 用作 Web 服务器,但是当前在 IIS Express W
error : Web 项目"RealEstate.Web"的 URL"http://localhost:20000"已配置为将 IIS 用作 Web 服务器 ...
- css那些事儿4 背景图像
background:背景颜色,图像,平铺方式,大小,位置 能够显示背景区域即为盒子模型的填充和内容部分,其中背景图像将会覆盖背景颜色.常见的水平或垂直渐变颜色背景通常使用水平或垂直渐变的背景图像在水 ...
- 父类与子类的转换as,is
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 初入py
1.下载工具sublime 我的网盘下载地址:https://pan.baidu.com/s/18-U1ZSg_zHoSAqUuvXj_PQ 直接解压即可 2.配置py27 在新建的文件里面编辑并保存 ...
- 解决编写 xml 没有代码提示
有时候在编写 struts.xml 会没有代码提示,一般是因为没有联网导致的,或者之前配置过 dtd 文件 url,但是文件路径之后被修改了. 解决方案有: 让电脑联网 修改 dtd 的本地路径以及 ...
- Qt入门实例
一.基于Qt设计师 1.创建一个GUI项目,选择“Qt4 Gui Application”.其中还有Empty Qt4 Project(空的工程),Qt4 Console Applicaiton(基于 ...