为什么标准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)…的意思吗?编译器对此做了什么?
虽然没有什么可以阻止您编写自己的helper,但我认为在库中提供make_shared<T>的主要原因是,它实际上创建了与shared_ptr<T>(new T)不同的内部共享指针类型,而shared_ptr<T>(new T)是不同的分配方式,如果没有专用的helper,就无法实现这一点。
Your make_unique wrapper on the other hand is mere syntactic sugar around a new expression, so while it might look pleasing to the eye, it doesn't bring anything new to the table. Correction: this isn't in fact true: Having a function call to wrap the new expression provides exception safety, for example in the case where you call a function void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&). Having two raw news 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 no make_unique in the standard: It was just forgotten. (This happens occasionally. There's also no global std::cbegin in the standard even though there should be one.)
还要注意unique_ptr接受第二个模板形参,您应该以某种方式允许它;这与shared_ptr不同,后者使用类型擦除来存储自定义删除器,而不使它们成为类型的一部分。
虽然没有什么可以阻止您编写自己的helper,但我认为在库中提供make_shared<T>的主要原因是,它实际上创建了与shared_ptr<T>(new T)不同的内部共享指针类型,而shared_ptr<T>(new T)是不同的分配方式,如果没有专用的helper,就无法实现这一点。
Your make_unique wrapper on the other hand is mere syntactic sugar around a new expression, so while it might look pleasing to the eye, it doesn't bring anything new to the table. Correction: this isn't in fact true: Having a function call to wrap the new expression provides exception safety, for example in the case where you call a function void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&). Having two raw news 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 no make_unique in the standard: It was just forgotten. (This happens occasionally. There's also no global std::cbegin in the standard even though there should be one.)
还要注意unique_ptr接受第二个模板形参,您应该以某种方式允许它;这与shared_ptr不同,后者使用类型擦除来存储自定义删除器,而不使它们成为类型的一部分。
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能做的唯一一件事就是稍微方便一些。仅此而已。
在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(更广为人知的是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草案中。