C++箴言:将new出来的对象存入智能指针

C++箴言:将new出来的对象存入智能指针,第1张

C++箴言:将new出来的对象存入智能指针,第2张

假设我们有一个获得处理优先级的函数,第二个函数根据优先级对动态分配的小部件进行一些处理:

int优先级();
void process widget(STD::tr1::shared _ ptr pw,int priority);

别忘了用对象来管理资源这句名言。processWidget使用智能指针(这里是tr1::shared_ptr)来处理动态分配的小部件。

现在考虑对processWidget的调用:

processWidget(新建小部件,priority());

等等,别这样打电话。它不能被编译。tr1::shared_ptr的构造函数取*指针(raw pointer)应该是显式的,所以不能从“new Widget”返回的*指针隐式转换为processWidget需要的tr1::shared_ptr。下面的代码仍然可以编译:

process Widget(STD::tr1::shared _ ptr(new Widget),priority());

令人惊讶的是,虽然我们在这里处处使用对象管理资源,但这个调用可能会泄漏资源。事情是这样发生的。

在编译器可以生成对processWidget的调用之前,它们必须传递实际参数来计算形参的值。第二个实参只是对函数priority的调用,但是第一个实参(" std::tr1::shared_ptr(new Widget)")由两部分组成。

表达式“新部件”的执行。

对tr1::shared_ptr的构造函数的调用。

在调用processWidget之前,编译器必须为这三件事生成代码:

调用优先级。

执行“新建小部件”。

调用tr1::shared_ptr的构造函数。

C++编译器允许在相当大的范围内决定完成这三件事的顺序。(这和Java、C#等语言的处理方式不同,函数参数总是按照确切的顺序计算。)表达式“new Widget”必须先执行,才能调用tr1::shared_ptr的构造函数,因为这个表达式的结果会作为参数传递给tr1::shared_ptr的构造函数,但是优先级的调用可以由第一个、第二个或者第三个来执行。如果编译器选择第二个来执行它(很可能这将使他们能够生成更高效的代码),我们最终会得到这样一个操作序列:

执行“新建部件”。

调用优先级。

调用tr1::shared_ptr的构造函数。

但是考虑一下如果优先级调用抛出异常会发生什么。在这种情况下,从“new Widget”返回的指针丢失了,因为它没有存储在tr1::shared_ptr中,我们期望它可以防止资源泄漏。因为在创建资源和将资源移交给资源管理对象之间可能会插入异常,所以调用processWidget可能会导致泄漏。避免类似问题的方法很简单:用单独的语句创建Widget并存储在智能指针中,然后将这个智能指针传递给processWidget:

std::tr1::shared_ptr pw(新Widget);//将新对象
//存储在
//独立语句中的智能指针中

processWidget(pw,priority());//这个电话不会泄露

这是因为编译器在不同语句之间重新安排操作顺序的空间比在一个语句内要小得多。“new Widget”表达式的调用和tr1::shared_ptr的构造函数与优先级的调用在不同的语句中,所以编译器不会允许优先级的调用插在它们之间。

要记住的事情

在独立语句中,新对象存储在智能指针中。如果忽略这一点,当异常发生时,可能会发生微妙的资源泄漏。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++箴言:将new出来的对象存入智能指针

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情