为什么标准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)...
究竟是什么意思?编译器对此做了什么?
6 回答
虽然没有什么可以阻止你编写自己的帮助器,但我相信在库中提供
make_shared<T>
的主要原因是它实际上创建了一个不同于shared_ptr<T>(new T)
的内部类型的共享指针,这是不同的分配,没有办法实现这一点专职助手 .另一方面,你的make_unique包装器仅仅是一个新表达式的语法糖,所以虽然看起来很悦目,但它并没有给表带来任何新东西 . Correction: 事实上并非如此:通过函数调用来包装
new
表达式可以提供异常安全性,例如在调用函数void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&)
的情况下 . 有两个原始new
s相互之间没有排序意味着如果一个新表达式失败并出现异常,另一个表达式可能会泄漏资源 . 至于为什么标准中没有make_unique
:它只是被遗忘了 . (偶尔会发生这种情况 . 标准中也没有全局std::cbegin
,即使应该有一个 . )另请注意
unique_ptr
采用第二个模板参数,您应该以某种方式允许;这与shared_ptr
不同,它使用类型擦除来存储自定义删除,而不会使它们成为类型的一部分 .在C 11中
...
也用于(在模板代码中)"pack expansion" .要求是将它用作包含未展开的参数包的表达式的后缀,并且它只是将表达式应用于包的每个元素 .
例如, Build 在您的示例上:
我认为后者是不正确的 .
此外,参数包可能不会传递给未展开的函数 . 我不确定一组模板参数 .
受到Stephan T. Lavavej实现的启发,我认为拥有一个支持数组范围的make_unique可能会很好,我很乐意对它进行评论 . 它允许您这样做:
C标准化委员会主席Herb Sutter写道:blog:
他还提供了与OP给出的实现相同的实现 .
Edit:
std::make_unique
现在是C++14的一部分 .很好,但Stephan T. Lavavej(更好地称为STL)为
make_unique
提供了更好的解决方案,它可以正常用于阵列版本 .这可以在his Core C++ 6 video上看到 .
STL版本的make_unique的更新版本现在可用作N3656 . 这个版本got adopted成为草案C 14 .
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
唯一能做的就是稍微方便一点 . 没有比这更好的了 .