C++ 使_独特和完美的转发

C++ 使_独特和完美的转发,c++,c++11,variadic-templates,unique-ptr,perfect-forwarding,C++,C++11,Variadic Templates,Unique Ptr,Perfect Forwarding,为什么标准C++11库中没有std::make_unique函数模板?我发现 std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3)); 我花了很长时间才把std::forward东西编译好,但我不确定它是否正确。它是?std::forward(args).的确切含义是什么?编译器对此做了什么?虽然没有什么可以阻止您编写自己的帮助程序,但我相信在库中提供make\u shared的主要原因是它实

为什么标准C++11库中没有
std::make_unique
函数模板?我发现

std::unique_ptr<SomeUserDefinedType> p(new SomeUserDefinedType(1, 2, 3));

我花了很长时间才把
std::forward
东西编译好,但我不确定它是否正确。它是?
std::forward(args).
的确切含义是什么?编译器对此做了什么?

虽然没有什么可以阻止您编写自己的帮助程序,但我相信在库中提供
make\u shared
的主要原因是它实际上创建了一种与
shared\u ptr(new T)
不同的内部共享指针类型,而
shared\u ptr(new T)
,没有专门的助手是无法实现这一目标的

另一方面,你的
make_unique
包装只是
new
表达式周围的语法糖分,因此,虽然它看起来很悦目,但它不会带来任何
new
更正:事实上并非如此:使用函数调用来包装
新的
表达式提供了异常安全性,例如在调用函数
void f(std::unique_ptr&&,std::unique_ptr&)的情况下。有两个未排序的原始
new
s意味着如果一个新表达式因异常而失败,另一个可能会泄漏资源。至于为什么标准中没有
make_unique:它只是被遗忘了。(这种情况偶尔会发生。标准中也没有全局
std::cbegin
,即使应该有一个。)


还请注意,
unique\u ptr
采用第二个模板参数,您应该以某种方式考虑该参数;这与
共享\u ptr
不同,后者使用类型擦除来存储自定义删除项,而不使它们成为类型的一部分。

而没有任何东西阻止您编写自己的帮助程序,我认为在库中提供
make_shared
的主要原因是它实际上创建了一种与
shared_ptr(new T)
不同的内部共享指针类型,这种类型的指针分配不同,如果没有专用的助手,就无法实现这一点

另一方面,你的
make_unique
包装只是
new
表达式周围的语法糖分,因此,虽然它看起来很悦目,但它不会带来任何
new
更正:事实上并非如此:使用函数调用来包装
新的
表达式提供了异常安全性,例如在调用函数
void f(std::unique_ptr&&,std::unique_ptr&)的情况下。有两个未排序的原始
new
s意味着如果一个新表达式因异常而失败,另一个可能会泄漏资源。至于为什么标准中没有
make_unique:它只是被遗忘了。(这种情况偶尔会发生。标准中也没有全局
std::cbegin
,即使应该有一个。)


还请注意,
unique\u ptr
采用第二个模板参数,您应该以某种方式考虑该参数;这与
shared_ptr
不同,后者使用类型擦除来存储自定义删除项,而不将它们作为类型的一部分。

std::make_shared
不仅仅是
std::shared_ptr ptr(新类型(…))的缩写。它做了一些没有它你做不到的事情

为了完成它的工作,
std::shared_ptr
除了保存实际指针的存储器外,还必须分配一个跟踪块。但是,由于
std::make_shared
分配实际对象,因此
std::make_shared
可能在同一内存块中同时分配对象和跟踪块

所以当
std::shared_ptr ptr=new Type(…)
将是两个内存分配(一个用于
新的
,一个在
std::shared_ptr
跟踪块中),
std::make_shared(…)
将分配一个内存块


这对于std::shared\u ptr的许多潜在用户来说都很重要。std::make_unique
唯一能做的就是稍微方便一点。仅此而已。

std::make_shared
不仅仅是std::shared_ptr ptr(新类型(…))的缩写。它做了一些没有它你做不到的事情

为了完成它的工作,
std::shared_ptr
除了保存实际指针的存储器外,还必须分配一个跟踪块。但是,由于
std::make_shared
分配实际对象,因此
std::make_shared
可能在同一内存块中同时分配对象和跟踪块

所以当
std::shared_ptr ptr=new Type(…)
将是两个内存分配(一个用于
新的
,一个在
std::shared_ptr
跟踪块中),
std::make_shared(…)
将分配一个内存块


这对于std::shared\u 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)
std::forward(args)…->标准::转发(1),标准::转发(2),
标准::转发(3)
标准::转发(参数…->标准::转发(1,2,3)
我认为后者是不正确的


此外,参数包不能传递给未展开的函数。我不确定是否有一组模板参数。

在C++11
中,
也用于(在模板代码中)“包扩展”

Th
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<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)
#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)...);
}
// 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);