可能的评估订单或Scott Meyers提供的资源泄漏是错误的吗?

时间:2015-12-29 11:58:21

标签: c++ c++11 memory-leaks

我正在阅读 Scott Meyers std::shared_ptr一书中的Effective Modern C++14。这是一个代码,其中作者说,潜在的资源泄漏可能是:

int computePriority(); // this function always throw an exception
// ...
processWidget(std::shared_ptr<Widget>(new Widget), // (S.M): potentital
              computePriority());                  // resource
                                                   // leak

Scott Meyers 表示可以在computePriority()new Widget之间调用std::shared_ptr<Widget>(expr)函数来评估将导致由{{1引起的内存泄漏的内容}}。不应该有一个序列点可以保证new表达式是否被评估,然后将评估new Widget?我想到这一点是因为在我看来这是正确的:序列点在std::shared_ptr<Widget>(expr)中将在没有排序的情况下评估所有它的参数(子表达式)并使共享指针准备就绪,然后做其他事情(无需排序即可评估其他参数)。如果这是不真实的,std::shared_ptr<Widget>(expr)是正确的(我仍然相信他,显然) ,这种行为会不正确?

是否有规则可以解释为什么这可能?我不擅长序列点,但告诉我他们的人说这应该是有效的。

4 个答案:

答案 0 :(得分:4)

排序并不意味着即时性 (在我上班之前,我的醒来是有序的,即使我穿好衣服并在中间吃早餐。)

参数的评估不是相互排序的。

也不是一个参数必须在另一个参数之前完全评估,而不管顺序如何。

也就是说,在shared_ptr构造函数之前对分配进行了排序,但是这些分配都没有针对另一个参数进行排序,并且不能保证分配和构造函数调用之间没有任何反应。

答案 1 :(得分:2)

  

不应该有一个序列点可以保证new Widget表达式是否被评估,然后将评估std::shared_ptr<Widget>(expr)

不,事实并非如此。 new Widgetshared_ptr构造之间没有序列点。

Sequence point。 (这是C ++ 11 BTW中过时的术语,但逻辑几乎保持不变。)

  

序列点出现了......

     
      
  1. 在评估&&(逻辑AND),||(逻辑OR)的左右操作数之间....

  2.   
  3. 评估三元的第一个操作数&#34;问号&#34;运算符和第二个或第三个操作数。 ....

  4.   
  5. 在完整表达结束时....

  6.   
  7. 在函数调用中输入函数之前....

  8.   
  9. 在函数返回....

  10.   
  11. 初始化程序结束时; ....

  12.   
  13. 每个声明者序列中的每个声明符之间....

  14.   
  15. 8.与输入/输出转换格式说明符关联的操作之后。 ....

  16.   

答案 2 :(得分:1)

  

不应该有一个序列点可以保证如果评估新的Widget表达式,那么接下来会评估std :: shared_ptr(expr)吗?

嗯,是的。分号很好,因为它标志着完整表达式的结束。

auto ptr = new Widget; // may throw bad_alloc
std::shared_ptr<Widget> shared(ptr); // may throw bad_alloc
processWidget(std::move(shared), computePriority()); // computePriority may throw   

这种方法的一个好处(将共享ptr的构造与new分开)是这样的构造函数保证删除在异常时传递给它的指针。

但是,如果可以的话,最好避免使用new,因为它可以更有效地分配(单个连续分配中的控制块和数据块),如果可以的话抛出异常,最终结果是函数没有效果(并且没有内存泄漏)

如果必须

,请选择以下语法
std::make_shared

因为两个函数调用从不交错,processWidget(std::make_shared<Widget>(), computePriority()); 可能会在computePriority()之前调用,反之亦然,如果抛出则没有内存泄漏。但是,使用make_shared块来围绕投掷调用可能符合您的利益,而不是通过内联来实现硬崩溃。

答案 3 :(得分:0)

请参阅http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr以获取参考
只要构造函数不会抛出bad_alloc,在构造函数中使用 Just a bunch of text here, at the end. yedyedyed 就可以了。 new A没有此问题(请参阅std::shared_ptr initialization: make_shared<Foo>() vs shared_ptr<T>(new Foo)