C ++使用C ++ 11分配shared_ptr(std :: shared_ptr):将shared_ptr初始化为临时变量仍然不好吗?

时间:2013-08-28 02:14:20

标签: c++ pointers c++11 shared-ptr smart-pointers

我正在阅读this answer,作者提到boost best practices,其中说:

  

避免使用未命名的shared_ptr临时值来保存输入;看看为什么   这很危险,请考虑这个例子:

void f(shared_ptr<int>, int); 
int g();

void ok() {
    shared_ptr<int> p(new int(2));
    f(p, g());
}

void bad() {
    f(shared_ptr<int>(new int(2)), g());
}
  

函数ok遵循字母的准则,而bad构造临时   shared_ptr到位,承认内存泄漏的可能性。以来   函数参数以未指定的顺序计算,这是可能的   首先评估新的int(2),g()秒,我们可能永远不会得到   如果g抛出异常,则为shared_ptr构造函数。 &LT; ...&GT;

     

上述异常安全问题也可以通过以下方式消除   使用中定义的make_shared或allocate_shared工厂函数   提升/ make_shared.hpp。这些工厂功能也提供了   通过合并分配来提高效率。

我想我会开始使用make_shared,但我想知道这一点建议是否仍适用于C ++ 11 shared_ptr。我问,因为我并不完全理解为什么投掷g()会阻止ctor被调用。

2 个答案:

答案 0 :(得分:9)

是的,C ++ 11的shared_ptr的工作方式相同。

  

我问,因为我并不完全理解为什么抛出g()会阻止ctor被调用。

你不理解什么?这是操作顺序问题,标准不要求特定订单。让我们将语句解压缩为一系列表达式:

auto __temp = new int(2);
auto &&__temp2 = g();
auto __temp3 = shared_ptr<int>(__temp);

你现在看到问题了吗?如果g抛出,则永远不会初始化__temp3。因此,__temp泄露

C ++标准不要求以这种方式解压缩语句。但它也不会禁止它。允许编译器自由地订购这些独立的表达式,但它认为合适。

答案 1 :(得分:4)

对于C ++ 11中的评估顺序,我认为没有任何改变。也就是说,除了只需要一个内存分配而不是两个内存分配外,使用std::make_shared<T>(...)是安全性方面更好的选择。

关于问题所在:以下对f()参数的评估是完全有效的:

  1. $tmp = new int(1)(使用$tmp表示提供的编译器,临时变量)
  2. g()
  3. std::shared_ptr<int>($tmp)
  4. 现在,如果g()抛出,则永远不会执行其他部分的评估,即永远不会构造std::shared_ptr<int>并且$tmp被泄露。