我正在阅读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被调用。
答案 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()
参数的评估是完全有效的:
$tmp = new int(1)
(使用$tmp
表示提供的编译器,临时变量)g()
std::shared_ptr<int>($tmp)
现在,如果g()
抛出,则永远不会执行其他部分的评估,即永远不会构造std::shared_ptr<int>
并且$tmp
被泄露。