问题实例
</br>
假设我们有一个函数用来揭示处理程序的优先权,另一个用来在根据优先级处理某个动态分配的对象。很自然地,我们认为需要使用RAII管理资源:1
2int priority();
void processWidget(shared_ptr<Widget> pw,int priority);
其执行操作如下:1
processWidget(new Widget,priority());
上述代码不能通过编译,因为到shared_ptr的构造函数是explict构造函数,无法通过隐式转换构造,因此必须写为如下类型:1
processWidget(shared_ptr<Widget>(new Widget),priority());
遗憾的是,尽管我们使用了RAII,但它照样可能导致资源泄漏。
问题说明
</br>
在调用process函数之前,编译器必须完成以下三件事:
- 调用priorty();
- 执行new Object;
- 调用shared_ptr构造函数
毫无疑问,2必然在3之前发生,关键在于无法确定1何时发生,也无法确定其是否会抛出异常。
举例而言,如果发生的顺序是213,并且在调用priorty()的时候抛出了一个异常,那new Widget返回的指针会遗失,因为在资源被创建和资源被转换为资源管理对象两个时间点间发生了异常干扰。
解决方案
</br>
解决方法很简单,就是分开执行:
- 以独立语句初始化RAII对象
- 将RAII对象作为参数传入函数
1 | shared_ptr<Widget> pw(new Widget); |
其能够正确实现的根本原因在于:编译器仅在单一语句内拥有决定执行先后次序的自由度。
总结
</br>
以独立语句将newed对象存入智能指针中,否则抛出的异常可能会导致资源泄漏。