在C ++ 1z中std :: make_unique和std :: make_shared的用处

时间:2017-07-27 20:26:58

标签: c++ c++17

使用C ++ 17,我们可以获得类模板的模板类型推导。因此,许多make函数可能会过时。

make_uniquemake_shared怎么样?

所以我们可以写

unique_ptr myPtr(new MyType());
// vs
auto myPtr = make_unique<MyType>();

我们可以忘记这些功能吗?

2 个答案:

答案 0 :(得分:20)

由于无法区分unique_ptrshared_ptrT*T[]都没有明确提供类型,因此无法构建。写unique_ptr{new int}是不正确的。

此外,std::make_shared不仅可以为您构建std::shared_ptr,还可以输入new。它还在单个分配中分配对象和控制结构,这为您节省了分配,并为您提供了何时必须更改引用计数的位置。

答案 1 :(得分:7)

您忘记了我们获得make_unique的最重要原因之一。考虑这两个函数调用之间的区别:

some_function(make_unique<T>(), std::vector<U>{1, 2, 3});
some_function(unique_ptr(new T()), std::vector<U>{1, 2, 3});

其中一个功能有一个微妙的错误。你能猜出它是什么吗?

如果vector构造函数抛出,那么可能会发生一些非常糟糕的事情。由于C ++函数参数表达式评估规则,评估顺序可能为new T(),后跟std::vector<U>{1, 2, 3}后跟unique_ptr<T>构造函数。如果vector抛出,则永远不会释放new ed指针。

那很糟糕。这大约有90%的原因我们都有make_unique

现在已经说过,C ++ 17 对函数参数表达式的评估进行了更改,这使得这一点过时了。 C ++ 17的规则保证在初始化参数的不同表达式之间不存在重叠。也就是说,每个参数的初始化表达式在另一个参数可以开始之前完全完成。 C ++ 17并不保证参数表达式的顺序,但子表达式之间不能交错。

在上面的代码中,评估顺序可以是vector,也可以是new T()。但如果它首先评估new T(),则必须在评估unique_ptr<T>()构造函数之前评估vector

所以在C ++ 17中,这两者都是安全的。因此,虽然模板参数推导不会过时make_unique,但C ++ 17作为一个整体可以。

当然,始终存在标准合规问题。在实现表达式评估排序规则之前,编译器可能会实现构造函数参数推导。如果表达式评估排序不存在,那么就无法使代码中断(除非您依赖于某些编译器不支持的功能测试宏)。< / p>

为了安全起见,我建议在这种情况下坚持make_unique

最后,make/allocate_shared的特殊功能是:在同一存储中分配控制块和对象的能力。这不是shared_ptr的不重要功能,无法使用模板new进行复制。

因此,您应尽可能继续使用make_shared