时间:2014.05.23
地点:基地
---------------------------------------------------------------------------------
一、常识
C/C++中函数在被调用时,函数的参数的执行顺序是不确定的。
---------------------------------------------------------------------------------
二、问题
假设有两个函数,一个揭示处理程序的优先权,还一个用于对动态分配所得的物件进行带有优先权的处理。两个函数声明如下:
int Priority(); void ProcessWidget(std::shared_ptr<Widget>pw,int Priority());
这里我们采用以对象管理资源的方式对得到的对象进行管理,我们知道shared_ptr构造函数是将一个原始指针包装起来,但构造函数本身是explicit的,无法将原始指针隐式转换为智能指针,而我们的ProcessWidget需要的是一个指针指针,于是可能想到的调用方法时这样:
ProcessWidget(std::shared_ptr<Widget>(new Widget),Priority());
这样看起来代码只有一行,但危机四伏,因为正如前面所说,这样调用函数时,两个参数到底先算谁是不确定的。这样的调用包括了三个部分:
1.执行new Widget表达式,得到一个原始指针
2.调用shraed_ptr的构造函数,包装原始指针
3.调用Priority函数
我们可以知道的仅仅是前两个步骤是先后执行的,但第3步是不确定的,比如这样的调用执行顺序是:123还是132还是312是无法预测的。在132这种情况下:如果第2步调用Priority函数发生了异常,而此时new已经new出了新的对象,但还没置入智能指针,即资源被创建后和资源被转换为资源管理对象之间的函数调用发生了异常,和会导致内存泄露。
---------------------------------------------------------------------------------
三、解决办法
一个简单地解决这种资源泄露问题的方案是:强制的使3的执行,必须在12之后,我们晓得,程序语句一般是按顺序执行的,由此,我们先函数参数中的两个大块分离出来,即:
第一大块
1.先创建对象
2.然后在将对象置入智能指针进行管理
第二大块
3.最后才把指针指针传给ProcessWidget进行处理
即:
std::shared_prt<Widget>pw(new Widget); ProcessWidget(pw,Priority());
---------------------------------------------------------------------------------
四、总结
我们知道编译器对于跨越语句的各项操作没有重新排列的自由,只能老老实实的按代码的编排执行,如果不这样,一旦有一步,异常抛出,就很有可能导致难以察觉的资源泄露。另外一方面,我觉得不仅仅是在对new出来的这种对象上分离处理,而且我们应该尽量避免函数的参数在函数的调用那一时,传递给函数的参数最好是以及确定下来无需在这一步计算了。
Effective 学习之以独立语句将newed对象置入智能指针