fre*_*low 215 c++ unique-ptr variadic-templates perfect-forwarding c++11
为什么std::make_unique标准C++ 11库中没有函数模板?我发现
std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));
Run Code Online (Sandbox Code Playgroud)
有点冗长.以下不是更好吗?
auto p = std::make_unique<SomeUserDefinedType>(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
这隐藏得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)...));
}
Run Code Online (Sandbox Code Playgroud)
我花了很std::forward长时间来编译这些东西,但我不确定它是否正确.是吗?究竟是什么std::forward<Args>(args)...意思?编译器对此做了什么?
Joh*_*åde 157
C++标准化委员会主席Herb Sutter在他的博客上写道:
C++ 11不包含
make_unique部分是一种疏忽,并且几乎肯定会在未来添加.
他还提供了与OP给出的实现相同的实现.
编辑: std::make_unique现在是C++ 14的一部分.
小智 77
很好,但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)...);
}
Run Code Online (Sandbox Code Playgroud)
这可以在他的Core C++ 6视频中看到.
STL版本的make_unique的更新版本现在可以作为N3656使用.这个版本被 C++ 14采用.
Ker*_* SB 19
虽然没有什么可以阻止你编写自己的帮助器,但我相信make_shared<T>在库中提供的主要原因是它实际上创建了一个不同的内部类型的共享指针shared_ptr<T>(new T),而不是分配,并且如果没有专用的话就没有办法实现这一点.帮手.
更正:事实上并非如此:使用函数调用来包装make_unique另一方面,你的包装器仅仅是一个new表达式的语法糖,所以尽管它看起来很悦目,但它并没有带来任何东西new.new表达式可以提供异常安全性,例如在调用函数的情况下void f(std::unique_ptr<A> &&, std::unique_ptr<B> &&).有两个new相对于彼此未经过排序的原始s意味着如果一个新表达式失败并出现异常,则另一个表达式可能会泄漏资源.至于为什么make_unique标准中没有:它只是被遗忘了.(偶尔会发生这种情况.std::cbegin标准中也没有全球性,即使应该有一个.)
另请注意,您unique_ptr需要以某种方式允许的第二个模板参数; 这与shared_ptr使用类型擦除来存储自定义删除器而不使它们成为类型的一部分不同.
Nic*_*las 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能做的就是稍微方便一点.没有比这更好的了.
Mat*_* M. 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)
Run Code Online (Sandbox Code Playgroud)
我认为后者是不正确的.
此外,参数包可能不会传递给未展开的函数.我不确定一组模板参数.
受到Stephan T. Lavavej实现的启发,我认为拥有一个支持数组范围的make_unique可能会很好,它在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);
Run Code Online (Sandbox Code Playgroud)