当前位置: 首页 > news >正文

C++学习笔记----6、内存管理(五)---- 智能指针(2)

        书接上回!

        make_unique()使用值初始化。例如,将初始类型初始化为0,对象为缺省构造。如果不需要这样的值初始化,例如,因为不管怎么样你都会覆写共初始值,你就可以省略值初始化,通过使用make_unique_for_overwrite()函数提高性能,该函数会使用缺省初始化值。对于初始类型,这意味着它们不会被初始化,会在内存中包含任何可能的值,而对象仍会是初始构造时的值。

        你也可以通过直接调用其构造函数来生成unique_ptr。注意Simple一定要用两次:

unique_ptr<Simple> mySimpleSmartPtr { new Simple{} };

        我们以前讨论过,模板值预测(CTAD)通常可以用于让编译器预测出模板类型的值,基于传递给类模板的构造函数的参数。例如,允许写出vector v{1,2}而不用vector<int> v{1,2}.CTAD对于unique_ptr不好使,所以不能省略模板类型参数。

        在c++17之前,只能使用make_unique()不仅仅是因为它意味着只能指定一次类型,还因为安全的原因!考虑以下对foo()函数的调用:

foo(unique_ptr<Simple> { new Simple{} }, unique_ptr<Bar> { new Bar { data() } });

        如果Simple或者Bar的构造函数或者data()函数抛出了一个例外,它依赖于你的编译器的优化,Simple或者Bar对象是可能会有内存渗露的。而对于make_unique()则不会有内存渗露:

foo(make_unique<Simple>(), make_unique<Bar>(data()))

        从c++17开始,对foo()的调用都是安全的,但是建议使用make_unique(),因为它易于阅读。

总是要用make_unique()来生成unique_ptr。

1.2、使用unique_ptr

        标准智能指针的一个最大的特点是它提供了许多的好处,不再要求用户去学习许多的新的语法。智能指针仍然能够像标准指针一样使用间接引用(使用*或者->)。例如,还是以前的例子,->操作符用于调用go()成员函数:

mySimpleSmartPtr-­>go();

与标准指针一样,也可以写成如下的语句:

(*mySimpleSmartPtr).go();

        get()成员函数也可以用于直接访问它包装的指针。这对于要求将指针传递给一个原始指针的情况会很有用。例如,假设你要使用如下的函数:

void processData(Simple* simple) { /* Use the simple pointer... */ }

你就可以像下面一样进行调用:

processData(mySimpleSmartPtr.get());

        可以对unique_ptr包装的指针进行释放,也可以用reset()将其指向另一个指针。举例如下:

mySimpleSmartPtr.reset();// Free resource and set to nullptr
mySimpleSmartPtr.reset(new Simple{}); // Free resource and set to a new
// Simple instance

        可以使用release()将unique_ptr包装的指针断开,返回包装指针指向的资源,然后将智能指针赋值为nullptr。非常有效,智能指针失去了对资源的控制,这样的话,在不再使用的时候,你就要负责将其资源进行释放!下面是一个例子:

Simple* simple { mySimpleSmartPtr.release() }; // Release ownership
// Use the simple pointer...
delete simple;
simple = nullptr;

        因为unique_ptr代表了唯一的属主,所以它不能被拷贝!但是,剧透一下,使用move的语法是可以将unique_ptr move给另一个的,这个我们以后再讨论。简单提一下,std::move()工具函数可以用于显式地将unique_ptr的属主进行转移,如下面的代码片断。别担心,其语法我们以后会讨论到,你会明白的。

class Foo
{
public:Foo(unique_ptr<int> data) : m_data { move(data) } { }
private:unique_ptr<int> m_data;
};auto myIntSmartPtr { make_unique<int>(42) };
Foo f { move(myIntSmartPtr) };

1.3、unique_ptr与C风格的数组

        unique_ptr可以保存动态分配的旧的C风格的数组。下面的例子生成了一个包含了动态分配的C风格的十个整数的数组的unique_ptr:

auto myVariableSizedArray { make_unique<int[]>(10) };

myVariableSizedArray的类型就是unique_ptr<int []>,支持用数组下标访问其元素。如下示例:

myVariableSizedArray[1] = 123;

        与非数组的情况一样,make_unique()对于数组的所有元素使用了值初始化,与std::vector类似。对于初始类型,这意味着初始化为0.如果不想生成缺省初始值的数组,可以调用make_unique_for_overwrite()函数,这意味着对于初始类型不进行初始化。要记住,要尽可能地避免不初始化数据,要理智使用。

        虽然可以使用unique_ptr来保存动态分配的C风格的数组,但还是推荐使用标准构造函数,如std::array或者vector。

1.4、对delete进行客户化

        缺省情况下,使用标准的new与delete操作符来分配与释放内存。但你可以改变这种行为,使用自己的分配与释放函数。当你 使用第三方C库时会很方便。例如,假设你有一个C库,要求你使用my_alloc()来分配内存,my_free()来释放内存:

int* my_alloc(int value) { return new int { value }; }
void my_free(int* p) { delete p; }

        为了在对的时间在分配了的资源上正确地调用my_fee(),可以使用带有客户化了的delete的unique_ptr:

unique_ptr<int, decltype(&my_free)> myIntSmartPtr { my_alloc(42), my_free };

        这段代码使用my_alloc()为整数分配了内存,通过调用my_free(),unique_ptr释放了内存。unique_ptr的这个属性对于非内存的其他资源的管理也很有用。例如,它可以用于自动关闭一个文件或者网络连接,或者任何其他资源,当unique_ptr不在活动范围时。

        不幸的是,unique_ptr的客户化的delete的语法有一点儿臃肿。需要指定客户化delete的类型作为模板类型参数,它应该是指向接受一个单独的指针作为参数的指针类型,并且返回void。在这个例子中,decltype(&my_free)用于返回my_free()函数的指针类型。使用带有shared_ptr的客户化的delete会更容易一点儿。我们明天会讨论的share_ptr会展示如何使用shard_ptr来自动关闭不在活动范围的文件。

http://www.lryc.cn/news/435586.html

相关文章:

  • 游戏出海迎新变局——海外游戏市场有哪些新趋势和新机遇?
  • 【Unity踩坑】创建新项目后提示编译错误要进入安全模式
  • SpringBoot开发——整合Logbook进行HTTP API请求响应日志输出
  • 【嵌入式开发 Linux 常用命令系列 7.1 -- git log 只显示日期和主题(title)和commit id】
  • Android Radio2.0——交通公告状态设置(二)
  • 用centos安装远程迅雷失败,重写程序做一台下载服务器
  • Mysql基础练习题 1407.排名靠前的旅行者(力扣)
  • 一维稳态与非稳态导热的详细分析
  • 以太坊开发环境
  • 深入理解Java虚拟机:Jvm总结-虚拟机字节码执行引擎
  • 第十一周:机器学习
  • 碰撞检测 | 详解圆-矩形碰撞检测与N圆覆盖模型(附ROS C++可视化)
  • pandas读取Excel文件单元格中的百分数时保持数据格式及精度
  • 【重学 MySQL】二十五、等值连接vs非等值连接、自连接vs非自连接
  • Springboot工程配置https访问
  • 智慧水务建设的核心内容
  • opencv之图像轮廓
  • shader 案例学习笔记之step函数
  • node快速复制文件或文件夹,排除部分文件(node_modules)
  • 网络层 VIII(网络层设备——路由器)【★★★★★★】
  • 302.AI学术论文搜索工具的智能体验
  • arm平台常用工具和动态库编译
  • 代码随想录训练营day45|115.不同的子序列,583. 两个字符串的删除操作,72. 编辑距离
  • 椋鸟C++笔记#7:标准模板库STL初识
  • 滴滴嘀嗒,出行行业响起Robotaxi“倒计时”
  • 【MATLAB源码-第264期】基于matlab的跳频通信系统仿真,采用MSK调制方式,差分解调;输出误码率曲线和各节点波形图。
  • 如何在多台电脑上同步 VSCode配置和插件
  • 深度优先算法,广度优先算法,hill climbing,贪心搜索,A*算法,启发式搜索算法是什么,比起一般搜索法算法有什么区别
  • 《python语言程序设计》2018版第8章第14题金融:信用卡号合法性 利用6.29题
  • QT 基础学习