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
到底是什么意思?编译器对此做了什么?
Why is there no std::make_unique
function template in the standard C++11 library? I find
std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));
a bit verbose. Wouldn't the following be much nicer?
auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3);
This hides the new
nicely and only mentions the type once.
Anyway, here is my attempt at an implementation of 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)...));
}
It took me quite a while to get the std::forward
stuff to compile, but I'm not sure if it's correct. Is it? What exactly does std::forward<Args>(args)...
mean? What does the compiler make of that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
C++ 标准化委员会主席 Herb Sutter 在他的博客中写道:
他还给出了一个与 OP 给出的实现相同的实现。
编辑:
std::make_unique
现在是 C 的一部分++14。Herb Sutter, chair of the C++ standardization committee, writes on his blog:
He also gives an implementation that is identical with the one given by the OP.
Edit:
std::make_unique
now is part of C++14.很好,但是 Stephan T. Lavavej(更广为人知的名称是 STL)对于
make_unique
有一个更好的解决方案,它可以在数组版本中正常工作。这可以在他的 Core C++ 6 视频中看到。
STL 版本的 make_unique 的更新版本现已作为 N3656 提供。此版本已被采用到 C++14 草案中。
Nice, but Stephan T. Lavavej (better known as STL) has a better solution for
make_unique
, which works correctly for the array version.This can be seen on his Core C++ 6 video.
An updated version of STL's version of make_unique is now available as N3656. This version got adopted into draft C++14.
std::make_shared
不仅仅是std::shared_ptr的简写。 ptr(新类型(...));
.它可以完成一些没有它就无法完成的事情。为了完成其工作,std::shared_ptr 除了保存实际指针的存储空间之外,还必须分配一个跟踪块。但是,由于
std::make_shared
分配实际对象,因此std::make_shared
可能同时分配对象和同一个内存块。因此,虽然 std::shared_ptrptr = new Type(...); 将是两个内存分配(一个用于
new
,一个用于std::shared_ptr
跟踪块),std::make_shared(...)
将分配一个内存块。这对于
std::shared_ptr
的许多潜在用户来说非常重要。std::make_unique
唯一能做的就是稍微方便一些。仅此而已。std::make_shared
isn't just shorthand forstd::shared_ptr<Type> ptr(new Type(...));
. It does something that you cannot do without it.In order to do its job,
std::shared_ptr
must allocate a tracking block in addition to holding the storage for the actual pointer. However, becausestd::make_shared
allocates the actual object, it is possible thatstd::make_shared
allocates both the object and the tracking block in the same block of memory.So while
std::shared_ptr<Type> ptr = new Type(...);
would be two memory allocations (one for thenew
, one in thestd::shared_ptr
tracking block),std::make_shared<Type>(...)
would allocate one block of memory.That is important for many potential users of
std::shared_ptr
. The only thing astd::make_unique
would do is be slightly more convenient. Nothing more than that.虽然没有什么可以阻止您编写自己的帮助程序,但我相信在库中提供
make_shared
的主要原因是它实际上创建了与shared_ptr
不同的内部类型的共享指针。 T>(new T)
,这是不同分配的,如果没有专门的助手,就无法实现这一点。另一方面,您的更正:这实际上不是真的:使用函数调用来包装make_unique
包装器只是new
表达式周围的语法糖,因此虽然它可能看起来赏心悦目,但它不会带来任何< code>new 到表中。new
表达式会产生异常安全性,例如在调用函数的情况下void f(std::unique_ptr &&, std::unique_ptr &&)
。拥有两个彼此未排序的原始 new 意味着,如果一个 new 表达式因异常而失败,则另一个可能会泄漏资源。至于为什么标准中没有make_unique
:它只是被遗忘了。 (这种情况偶尔会发生。标准中也没有全局std::cbegin
,尽管应该有一个。)另请注意,
unique_ptr
采用第二个模板参数,您应该使用它以某种方式允许;这与shared_ptr
不同,后者使用类型擦除来存储自定义删除器,而不使它们成为类型的一部分。While nothing stops you from writing your own helper, I believe that the main reason for providing
make_shared<T>
in the library is that it actually creates a different internal type of shared pointer thanshared_ptr<T>(new T)
, which is differently allocated, and there's no way to achieve this without the dedicated helper.YourCorrection: this isn't in fact true: Having a function call to wrap themake_unique
wrapper on the other hand is mere syntactic sugar around anew
expression, so while it might look pleasing to the eye, it doesn't bring anythingnew
to the table.new
expression provides exception safety, for example in the case where you call a functionvoid f(std::unique_ptr<A> &&, std::unique_ptr<B> &&)
. Having two rawnew
s that are unsequenced with respect to one another means that if one new expression fails with an exception, the other may leak resources. As for why there's nomake_unique
in the standard: It was just forgotten. (This happens occasionally. There's also no globalstd::cbegin
in the standard even though there should be one.)Also note that
unique_ptr
takes a second template parameter which you should somehow allow for; this is different fromshared_ptr
, which uses type erasure to store custom deleters without making them part of the type.在 C++11 中
...
也用于(在模板代码中)“包扩展”。要求是您将其用作包含未展开参数包的表达式的后缀,并且它将简单地将表达式应用于该包的每个元素。
例如,以您的示例为基础:
我认为后者是不正确的。
此外,参数包不能传递给未扩展的函数。我不确定一组模板参数。
In C++11
...
is used (in template code) for "pack expansion" too.The requirement is that you use it as a suffix of an expression containing an unexpanded pack of parameters, and it will simply apply the expression to each of the elements of the pack.
For example, building on your example:
The latter being incorrect I think.
Also, pack of arguments may not be passed to a function unexpanded. I am unsure about a pack of template parameters.
受到 Stephan T. Lavavej 实现的启发,我认为拥有一个支持数组范围的 make_unique 可能会很好,它在 github 上,我很想得到关于它的评论。它允许您执行以下操作:
Inspired by the implementation by Stephan T. Lavavej, I thought it might be nice to have a make_unique that supported array extents, it's on github and I'd love to get comments on it. It allows you to do this: