make_unique和完美的转发

为什么标准C ++ 11库中没有std::make_unique函数模板? 我发现

 std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3)); 

有点冗长。 以下不会更好吗?

 auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3); 

这隐藏了new很好,只提到一次类型。

无论如何,这是我尝试执行make_unique

 template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); } 

我花了相当长的时间才得到std::forward东西来编译,但我不确定是否正确。 是吗? std::forward<Args>(args)...是什么意思? 编译器做了什么?

C ++标准化委员会主席Herb Sutter在他的博客上写道:

C ++ 11不包含make_unique部分是一个疏忽,将来肯定会增加。

他还给出了与OP给出的相同的实现。

编辑: std::make_unique现在是C ++ 14的一部分。

不错,但是Stephan T. Lavavej(更好的称为STL)有更好的make_unique解决方案,可以正常工作。

 #include <memory> #include <type_traits> #include <utility> template <typename T, typename... Args> std::unique_ptr<T> make_unique_helper(std::false_type, Args&&... args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); } template <typename T, typename... Args> std::unique_ptr<T> make_unique_helper(std::true_type, Args&&... args) { static_assert(std::extent<T>::value == 0, "make_unique<T[N]>() is forbidden, please use make_unique<T[]>()."); typedef typename std::remove_extent<T>::type U; return std::unique_ptr<T>(new U[sizeof...(Args)]{std::forward<Args>(args)...}); } template <typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) { return make_unique_helper<T>(std::is_array<T>(), std::forward<Args>(args)...); } 

这可以在他的Core C ++ 6视频中看到。

STL的make_unique版本的更新版本现在可作为N3656使用 。 这个版本被采纳到草稿C ++ 14中。

虽然没有什么能阻止你编写自己的帮助器,但我相信在库中提供make_shared<T>主要原因是它实际上创建了一个不同于shared_ptr<T>(new T)内部类型的共享指针,没有专门的帮手,没有办法实现这一点。

另一方面,你的make_unique包装仅仅是一个new表达式的语法糖,所以虽然它看起来很悦目,但它并没有带来任何new的东西。 更正:这不是真的:有一个函数调用来包装new表达式提供了异常的安全性,例如在你调用函数void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&) 。 有两个彼此不相关的原始new的意味着,如果一个新的表达式失败,例外,另一个可能会泄漏资源。 至于为什么这个标准没有make_unique :它只是被遗忘了。 (偶尔会发生这种情况,即使应该有一个,标准中也没有全局的std::cbegin 。)

另外请注意, unique_ptr需要第二个模板参数,你应该允许; 这与shared_ptr不同,它使用类型擦除来存储自定义删除器,而不使其成为类型的一部分。

std::make_shared不只是std::shared_ptr<Type> ptr(new Type(...));简写std::shared_ptr<Type> ptr(new Type(...)); 。 它做了一些你离不开的东西。

为了完成它的工作, std::shared_ptr必须分配一个跟踪块,并保存实际指针的存储空间。 但是,因为std::make_shared分配了实际的对象,所以std::make_shared有可能把对象跟踪块分配在同一块内存中。

所以虽然std::shared_ptr<Type> ptr = new Type(...); 将是两个内存分配(一个new ,一个在std::shared_ptr跟踪块), std::make_shared<Type>(...)将分配一块内存。

这对std::shared_ptr许多潜在用户很重要。 std::make_unique唯一能做的就是稍微方便一点。 没有什么比这更多。

在C ++ 11中...被用于(在模板代码中)“包扩展”。

要求是将其用作包含未展开的参数包的表达式的后缀,并且它将简单地将表达式应用于包的每个元素。

例如,建立你的例子:

 std::forward<Args>(args)... -> std::forward<int>(1), std::forward<int>(2), std::forward<int>(3) std::forward<Args...>(args...) -> std::forward<int, int, int>(1,2,3) 

后者是错误的,我想。

另外,一组参数可能不会传递给未展开的函数。 我不确定一些模板参数。

受Stephan T. Lavavej实现的启发,我认为make_unique支持数组范围可能是不错的, 它在github上 ,我很想得到它的评论。 它允许你这样做:

 // create unique_ptr to an array of 100 integers auto a = make_unique<int[100]>(); // create a unique_ptr to an array of 100 integers and // set the first three elements to 1,2,3 auto b = make_unique<int[100]>(1,2,3);