假设某个函数用来揭示程序的优先权,另一个函数用来在某个动态分配所得Widget上进行某些带有优先权的处理,并且“以对象管理资源”,即processWdiget决定对其动态分配而来的Widget运用智能指针:
int priority();
void processWidget(std::tr1::shared_ptr<Widget> pw,int priority);
//调用
processWidget(std::tr1::shared_ptr<Widget>(new Widget),priority())
对于上述的调用语句,虽然使用了对象管理资源,却发生内存泄露。
对于上述调用语句,编译器必须创建代码做以下三件事:
- 调用priority
- 执行“new Widget”
- 调用tr1::shared_ptr构造函数
C++编译器对于什么样的次序完成这样的事情,弹性很大。这和其他语言如java和C#不同,那两种语言总是以特定次序完成函数参数的核算。对于“new Widget”一定执行与shared_ptr之前,因为这个表达式的结果还要被传入作为shared_ptr构造函数的一个实参,但对priority的调用则排在第一或第二或第三执行,这是未确定的事情,如果执行的顺序如下:
- 执行“new Widget”
- 调用priority
- 调用tr1::shared_ptr构造函数
如果priority调用发生异常,new Widget返回的指针将会遗失,导致内存泄漏。
避免这类的问题方法很简单:使用分离语句,分别写出1、创建Widget,2、将它置入智能指针,然后再把那个智能指针传给processWidget:
std::tr1::shared_ptr<Widget> pw(new Widget); //单独语句嫩以智能指针存储newed所得对象
processWidget(pw,priority()); //这个调用动作不会导致内存泄露
总结
- 以独立语句将newed对象储存于(置入)智能指针内,如果不这么做,一旦异常被抛出,有可能导致难以察觉的资源泄露。