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

C++ C++;使用C+分配共享的ptr+;11(std::shared_ptr):将shared_ptr初始化为临时变量仍然不好吗?,c++,pointers,c++11,shared-ptr,smart-pointers,C++,Pointers,C++11,Shared Ptr,Smart Pointers,我正在阅读,作者提到的是: 避免使用未命名的共享临时文件来保存键入内容;看看原因 这是危险的,考虑这个例子: void f(共享,int); int g(); void ok(){ 共享ptr p(新int(2)); f(p,g()); } 无效坏(){ f(shared_ptr(newint(2)),g()); } 函数ok严格遵循指导原则,而bad构造临时函数 共享ptr到位,允许内存泄漏的可能性。自从 函数参数按未指定的顺序求值,这是可能的 首先计算新的int(2),然后计算g(),我们

我正在阅读,作者提到的是:

避免使用未命名的共享临时文件来保存键入内容;看看原因 这是危险的,考虑这个例子:

void f(共享,int);
int g();
void ok(){
共享ptr p(新int(2));
f(p,g());
}
无效坏(){
f(shared_ptr(newint(2)),g());
}
函数ok严格遵循指导原则,而bad构造临时函数 共享ptr到位,允许内存泄漏的可能性。自从 函数参数按未指定的顺序求值,这是可能的 首先计算新的int(2),然后计算g(),我们可能永远不会得到 如果g抛出异常,则发送到共享的ptr构造函数

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


我想我会开始使用
make_shared
,但我想知道这条建议是否仍然适用于C++11
shared_ptr
。我问这个问题是因为我真的不完全理解为什么抛出
g()
会阻止调用ctor。

是的,C++11的
shared\u ptr
也是这样工作的

我这样问是因为我不完全理解为什么抛出g()会阻止调用ctor

你还不明白什么?这是一个操作顺序问题,标准不要求特定的顺序。让我们将语句解包为一系列表达式:

auto __temp = new int(2);
auto &&__temp2 = g();
auto __temp3 = shared_ptr<int>(__temp);
auto\uu temp=newint(2);
自动&&_temp2=g();
自动温度3=共享温度(温度);
你现在看到问题了吗?如果
g
抛出,则将永远不会初始化
\u temp3
。因此,
\u temp
将被泄漏


C++标准不要求以这种方式解压缩语句。但它也不禁止这样做。编译器可以自由地对这些独立表达式进行排序,不管它认为合适与否。

我认为C++11中的计算顺序没有任何变化。也就是说,除了只需要一次而不是两次内存分配之外,使用
std::make_shared(…)
在安全方面是更好的选择

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

  • $tmp=newint(1)
    (使用
    $tmp
    指示编译器提供的临时变量)
  • g()
  • std::共享\u ptr($tmp)

  • 现在,如果
    g()
    抛出,那么其他部分的评估就永远不会执行,也就是说,
    std::shared_ptr
    永远不会被构造,并且
    $tmp
    被泄漏。

    我不能要求更好的解释,这真的出乎意料(对我来说)这样的东西的“解包顺序”并不总是一样的。另外,我还没有机会对右值引用有一个正确的理解。@StevenLu:右值引用与此无关。我只是使用了
    auto&
    来捕获
    g()
    的结果,以便在调用函数时可以正确地转发它。它与操作的顺序无关。而且,顺序可能是一样的。。。我知道函数参数的求值顺序是未定义的,但是一旦编译器决定求值第一个参数和
    shared_ptr
    构造函数,它就不必一直求值到最后(也就是说,作为构造函数求值的一部分,只尝试求值
    new
    ). 未定义的求值顺序真的执行嵌套函数调用的多个层次吗?@ChristianRau,它不必执行,因为标准没有规定它必须执行任何操作。所需的是1.9[#15]。@Nicolas实际上,单个编译器可以为优化目的对其进行不同的重新排序。或者,如果编译器可以证明代码没有资源争用,那么实际并行执行它(我不认为任何编译器/体系结构会这样做?)。
    auto __temp = new int(2);
    auto &&__temp2 = g();
    auto __temp3 = shared_ptr<int>(__temp);