C++用C++11分配shared_ptr(std::shared_ptl):将shared_ptr初始化为临时变量仍然

C++ allocating shared_ptr with C++11 (std::shared_ptr): Is it still bad to initialize the shared_ptr into a temporary variable?

本文关键字:shared ptr 初始化 变量 C++11 std ptl C++ 分配      更新时间:2023-10-16

我读到了这个答案,作者提到了boost最佳实践,其中写道:

避免使用未命名的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到位,承认内存泄漏的可能性。自从函数参数是按未指定的顺序计算的,这是可能的对于先计算new int(2),再计算g(),我们可能永远不会得到如果g抛出异常,则返回到sharedptr构造函数<gt;

上述异常安全问题也可以通过使用中定义的makeshared或allocate_shared工厂函数boost/make_shared.hp.这些工厂函数还提供通过合并拨款提高效率。

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

是的,C++11的shared_ptr也以同样的方式工作。

我之所以这么问,是因为我真的不完全理解为什么抛出g()会阻止调用ctor。

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

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

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

C++标准不要求以这种方式对语句进行解包。但它也没有禁止它。编译器可以自由地按自己认为合适的方式对这些独立表达式进行排序。

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

关于什么问题:以下对f()论点的评估是完全有效的:

  1. $tmp = new int(1)(使用$tmp表示编译器提供的临时变量)
  2. g()
  3. std::shared_ptr<int>($tmp)

现在,如果g()抛出,则永远不会执行对其他部分的评估,即永远不会构造std::shared_ptr<int>,并且$tmp被泄漏。