使用C ++ 17,我们可以获得类模板的模板类型推导。因此,许多make
函数可能会过时。
make_unique
和make_shared
怎么样?
所以我们可以写
unique_ptr myPtr(new MyType());
// vs
auto myPtr = make_unique<MyType>();
我们可以忘记这些功能吗?
答案 0 :(得分:20)
由于无法区分unique_ptr
和shared_ptr
,T*
和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
。