最近开始看《Effective C++》,为了方便以后回顾,特意做了笔记。若本人对书中的知识点理解有误的话,望请指正!!!
假设我们有个函数用来表示处理程序的优先权,另一个函数用来在某动态分配所得的 Widget
上进行某些带有优先权的处理:
int priority();
void processWidget(shared_ptr<Widget> pw, int priority);
//调用形式一:错误的,参数不匹配,编译器报错
processWidget(new Widget, priority());
//调用形式二:编译器通过,但有可能泄露资源
processWidget(shared_ptr<Widget>(new Widget), priority());
//调用形式三:最佳的方式,在单独语句内以智能指针存储new的对象
shared_ptr<Widget> pw(new Widget);
processWidget(pw, priority());
-
调用方式一
它不能通过编译。因为
shared_ptr
构造函数需要一个原始指针,但该构造函数是个explicit
构造函数,无法进行隐式转换。 -
调用方式二
编译器产出一个
processWidget
调用码之前,必须首先检查即将被传递的各个实参。processWidget
的第二实参只是一个单纯的对priority()
函数的调用,但第一实参shared_ptr<Widget>(new Widget)
由两部分组成:- 执行
new Widget
表达式 - 调用
shared_ptr
构造函数
于是在调用
processWidget
之前,编译器必须创建代码,做以下三件事:- 调用
priority()
- 执行
new Widget
表达式 - 调用
shared_ptr
构造函数
C++编译器以什么样的顺序完成这些事呢?弹性很大,但可以确定的是,”执行
new Widget
表达式“肯定在”调用shared_ptr
构造函数“之前,对”调用priority()
“则可以排在第一或第二或第三执行。若编译器选择以第二顺位执行priority()
,最终的顺序为:执行new Widget
表达式——>调用priority()
——>调用shared_ptr
构造函数。如果对
priority()
的调用导致异常,将会使new Widget
返回的指针遗失,因为它还未被置入shared_ptr
内,后者是我们用来防止资源泄漏的武器。所以在对processWidget
的调用过程中可能导致资源泄漏,因为在”资源被创建“和”资源被转换为资源管理对象“两个时间点之间有可能发生异常干扰。 - 执行
-
调用方式三
为了避免调用方式二中可能发生的资源泄漏,需要使用分离语句。因为编译器对 “跨越语句的各项操作” 没有重新排列的自由。方式三中的”执行
new Widget
表达式“和”调用shared_ptr
构造函数“这两个动作,和”调用priority()
“是分隔开来的,位于不同语句内,所以编译器不得在它们之间任意选择执行顺序。
Note:
- 以独立语句将newed对象存储于智能指针内,若不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏