为什么标准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)...
究竟是什么意思?编译器做了什么?
答案 0 :(得分:155)
C ++标准化委员会主席Herb Sutter写了他的blog:
C ++ 11不包括
make_unique
部分是一种疏忽,将来几乎肯定会加入。
他还提供了与OP给出的实现相同的实现。
修改 std::make_unique
现在是C++14的一部分。
答案 1 :(得分:76)
很好,但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)...);
}
这可以在his Core C++ 6 video上看到。
STL的make_unique版本的更新版本现在可用N3656。这个版本got adopted成为草案C ++ 14。
答案 2 :(得分:19)
虽然没有什么可以阻止你编写自己的帮助器,但我相信在库中提供make_shared<T>
的主要原因是它实际上创建了一个不同于shared_ptr<T>(new T)
的内部类型的共享指针,这是如果没有专门的帮助,就没有办法实现这一目标。
另一方面,你的 更正:这实际上并不正确:有一个函数调用来包装make_unique
包装器仅仅是new
表达式周围的语法糖,所以虽然它看起来很悦目,却没有带来任何东西{{1}到表。new
表达式提供了异常安全性,例如在你的情况下调用函数new
。有两个原始void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&)
相对于彼此没有排序意味着如果一个新表达式失败并出现异常,另一个表达式可能会泄漏资源。至于为什么标准中没有new
:它只是被遗忘了。 (偶尔会发生这种情况。标准中也没有全局make_unique
,即使应该有一个。{/ p>
另请注意std::cbegin
采用第二个模板参数,您应该以某种方式允许;这与unique_ptr
不同,shared_ptr
使用类型擦除来存储自定义删除,而不会将其作为类型的一部分。
答案 3 :(得分:19)
std::make_shared
不仅仅是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
唯一能做的就是稍微方便一点。没有比这更好的了。
答案 4 :(得分:13)
在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)
我认为后者不正确。
此外,参数包可能无法传递给未展开的函数。我不确定一组模板参数。
答案 5 :(得分:5)
受到Stephan T. Lavavej实施的启发,我认为拥有一个支持数组范围的make_unique可能会很好,it's on 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);