Effective C++ 读书笔记 Item17 在单独的语句中将new的对象放入智能指针

探讨C++中智能指针与资源管理的问题,解释为何即使使用智能指针仍可能发生资源泄漏,并提供解决方案。

假设我们有如下函数:

int priority();  //返回处理优先级
void processWidget(std::shared_ptr<Widget> pw, int priority); //处理对象根据不同优先级

现在用如下的语句调用这些函数:

processWidget(new Widget, priority());

这句调用必然会导致编译器报错,因为除非定义过隐式转换的运算符,裸指针对象不能被隐式转换为智能指针对象,下面才是语法正确的调用方式:

processWidget(std::shared_ptr<Widget>(new Widget), priority());

重点来了,即使你在这里使用了智能指针,内存泄漏依然有发生的可能。

震惊?我们先来看编译器的工作原理。编译器在生成对processWidget函数的调用之前,必须先解析其中的参数。这里我们有两个参数,分别是智能指针的构造函数和整型的函数priority()。在调用智能指针的构造函数之前,编译器又必须先要解析其中的new Widget语句,因此解析该函数的参数分为三步:

  • 调用priority()函数
  • 执行new语句
  • 调用智能指针构造函数

不像Java或者C#的编译器只会以固定的顺序解析参数,C++编译器多种多样,而且根据优化选项的不同,编译器可能会改变这三步的执行顺序,以此利用指令流水线停顿的周期(pipeline stall),获得更高效率的代码。但不论如何改变,底线是new语句必须提前于智能指针的构造函数,所以假设我们的编译器生成的机器代码实际执行了这样的顺序:

  1. 执行new语句
  2. 调用priority()函数
  3. 调用智能指针函数

如果priority()函数抛出了异常呢?那么从new语句动态分配的资源在到达智能指针构造函数之前就会泄露了。解决方法也很简单,使用一个单独的语句来创建智能指针对象:

std::shared_ptr<Widget> pw(new Widget); //放在单独的语句里
processWidget(pw,priority());  //这样就不会泄露资源了

编译器是逐语句编译的,通过使用一个单独的语句来构造智能指针对象,编译器就不会随意改动解析顺序,保证了生成的机器代码顺序是异常安全的,以及这样的代码写出来也更加美观。

总结:

  • 用一个单独的语句把裸指针储存到智能指针中。否则资源泄漏可能就会这么意想不到地发生了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值