使用C++ 17,我们可以获得类模板的模板类型推导.所以许多make功能可能会过时.
如何make_unique与make_shared?
所以我们可以写
unique_ptr myPtr(new MyType());
// vs
auto myPtr = make_unique<MyType>();
Run Code Online (Sandbox Code Playgroud)
那么我们可以忘记那些功能吗?
Bar*_*rry 20
在没有明确提供类型的情况下既unique_ptr不能也不可shared_ptr构造,因为无法区分T*和T[].写作unique_ptr{new int}是不正常的.
此外,std::make_shared不仅仅是std::shared_ptr为您构建一个,而无需您输入new.它还在单个分配中分配对象和控制结构,这为您节省了分配,并为您提供了何时必须更改引用计数的位置.
你忘记了我们得到的最重要的原因之一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});
Run Code Online (Sandbox Code Playgroud)
其中一个函数有一个微妙的错误.你能猜出这是什么?
如果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作为一个整体.
当然,始终存在标准合规性问题.在实现表达式求值排序规则之前,编译器可能会实现构造函数参数推导.如果不存在表达式评估排序,则无法使代码中断(除非您依赖于某些编译器不支持的功能测试宏).
所以为了安全起见,我建议坚持make_unique这种情况.
最后,还有一个特殊功能make/allocate_shared:能够在同一存储中分配控制块和对象.这不是一个不重要的功能shared_ptr,它不能与模板一起复制new.
所以你应该尽可能地继续使用make_shared.
| 归档时间: |
|
| 查看次数: |
799 次 |
| 最近记录: |