独特和完美的转发
为什么标准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
东西来编译,但我不确定它是否正确。 是吗? std::forward<Args>(args)...
意味着什么? 编译器对此做了什么?
Herb Sutter,C ++标准化委员会主席在他的博客上写道:
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视频中看到。
N3656现在提供STL版本的make_unique的更新版本。 该版本已被采纳为草案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
不同,它使用类型擦除来存储自定义删除程序,而不使其成为类型的一部分。