您的位置:首页 > 其它

第17条:以独立语句将new创建的对象存储在智能指针中

2014-12-12 21:18 176 查看
假设有一个函数用来显示处理程序的优先级,另一个函数根据当前优先级为一个动态分配的 Widget 做一些处理:
int priority();
void processWidget(std::tr1::shared_ptr<Widget> pw, int priority);

谨记“以对象管理资源”(参见第 13 条)。 processWidget 中可以使用智能指针来动态分配其需要处理的 Widget 。
下面是对 progressWidget 的一次调用:
processWidget(new Widget, priority());

请稍等,这样调用将不会通过编译。 tr1::shared_ptr 的构造函数中包含了一个 explicit 的裸指针(rawpointer),于是便不存在从“ new Widget ”语句返回的裸指针到 processWidget 所需的 tr1::shared_ptr 的隐式转换。然而下边的代码将顺利通过编译:
processWidget(std::tr1::shared_ptr<Widget>(new Widget),priority());

看上去有些令人吃惊,虽然在此我们使用“对象来管理资源”,上述调用却可能泄漏资源。后面会详细解释。
编译器产生一个 processWidget 调用之前,它必须评估传入的各实参。第二个参数仅仅调用了一个函数 priority ,但是第一个参数(“ std::tr1::shared_ptr<Widget>(newWidget) ”)包含两部分:
1、运行 “new Widget”表达式
2、调用 tr1::shared_ptr 的构造函数
因此,在调用processWidget之前,编译器必须创建代码解决下面的三件事情:
1、调用 priority 。
、执行 “new Widget” 。
3、调用 tr1::shared_ptr 构造函数。

C++编译器对这三项任务完成顺序要求宽松。(这一点与Java和C#不同,这两门语言中的函数参数总是以一个特定的顺序得到评估。)由于“ new Widget ”语句为 tr1::shared_ptr 的构造函数传递了一个参数,因此它必须在 tr1::shared_ptr 的构造函数被调用之前得到执行。但是调用 priority 的工作可以放到第一,第二,也可以放在最后。如果编译器决定第二个处理它(这样可以使代码更高效),我们就会得到这样的执行序列:
1. 执行 “ new Widget ” .
2. 调用 priority 。
3. 调用 tr1::shared_ptr 的构造函数。

但是如果调用 priority 时抛出了一个异常,将会发生些什么?在这种情况下,由于“ new Widget ”返回的指针不会如愿保存在 tr1::shared_ptr 中,于是内存泄漏就发生了。在“资源被创建”和“资源被转换为资源管理对象”这段时间内,有如果发生异常,那么调用 processWidget 就会造成资源泄漏。
防止这类问题办法简单:使用单独的语句,1、创建Widget 并存入一个智能指针,2、把智能指针传递给 processWidget :
<pre name="code" class="cpp">std::tr1::shared_ptr<Widget> pw(new Widget);
// 在一个单独的语句中创建 Widget 并存入一个智能指针
processWidget(pw, priority());    // 这样调用就不会内存泄漏。


这样可行,因为编译器为“多行的语句安排执行顺序”要比“单一语句”严格得多。在这段改进的代码中,“ new Widget ”语句以及对 tr1::shared_ptr 的构造函数的调用在单独的语句中,对 priority 的调用在另一个单独的语句中,所以编译器就没有机会调换处理顺序了。

需要记住的:
	在单独的语句中使用智能指针来保存由new创建的对象(以独立语句将new创建的对象存储于智能指针内)。否则,在异常时发生时会资源泄漏。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐