0.概述
以独立语句将newed对象存储于(置入)智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。
总而言之言而总之:将newed对象放入智能指针时,如果写在一起由于编译器会自己决定执行顺序,可能发生资源泄露,所以最好写成独立语句。
1.举例
processWidget用来在某动态分配所得的Widget上进行某些带有优先级的处理
int priority();
void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);
鉴于Item13:以对象管理资源,processWidget对其动态分配得来的Widget运用智能指针
调用processWidget:
processWidget(new Widget,priority());
以上形式不能通过编译:tr1::shared_ptr构造函数需要一个原始指针,但是该构造函数是explicit无法进行隐式转换,将得自"new Widget"的原始指针转换为要求的tr1::shared_ptr,如下可以通过编译:
processWidget(std::tr1::shared_ptr<Widget>(new Widget),priority());
虽然使用了对象管理资源,但是上面的调用可能会造成资源泄露
2.原因解释
在调用processWidget之前,编译器先创建代码,做以下三件事:
- 调用priority
- 执行“new widget"
- 调用tr1 : :shared ptr构造函数
这三项操作的执行顺序是不确定的,可以确定的是“new Widget”一定执行于tr1::shared ptr构造函数被调用之前,因为这个表达式的结果还要被传递作为tr1::shared_ptr构造函数的一个实参,但对priority的调用不确定,如果是下面这种情况:
- 执行“new widget"
- 调用priority
- 调用tr1::shared ptr构造函数
这种情况下如果priority调用异常,new Widget返回的指针会被遗失,因为尚未被置入tr1::shared ptr内。总结起来就是:在“资源被创建(经由“new widget")”和“资源被转换为资源管理对象”两个时间点之间有可能发生异常干扰。
3.解决方案
使用分离语句,分别写出
- 创建widge
- 将它置入一个智能指针内,然后再把那个智能指针传给processWidget
std::tr1::shared_ptr<Widget> pw(new Widget);
processWidget(pw, priority());
这之所以行得通原因在于编译器对于跨越语句的各项操作没有重新排列的自由。