1

给定以下来自“The C++ Programming language 4th edition”的函数模板:

template <typename TT, typename A>
unique_ptr<TT> make_unique(int i, A && a)
{
      return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }};
} 

我发现很难理解它实际上做了什么,

a 绝对是一个右值,因此 make_unique 函数似乎在堆上分配其内容并将该地址保存在 unique_ptr 中,因此我们不必担心删除它。但是,标准库的转发功能是做什么的?(我想这与存在右值有关)我尝试阅读 C++ 文档,但我似乎没有正确理解这一点。很想从更有经验的 C++ 程序员那里得到一个很好的解释。

谢谢!

4

2 回答 2

2

嗯...我很确定这不是作为 future 的变通实现std::make_unique,但无论如何,该函数的作用很容易理解,尽管它要求您具有新 C++ 的先验知识11个特点。

template <typename TT, typename A>
unique_ptr<TT> make_unique(int i, A && a)
{
      return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }};
}

首先make_unique是一个函数模板,我真的希望你已经知道了,如下所示要求你至少对模板的作用和模板的工作方式有最基本的了解。

现在到重要的部分。A && a有一个函数参数。具体来说,a是函数参数,其类型为A&&r -value reference。由于它的类型是模板类型参数,我们可以从调用者作为参数传递给a. 每当我们有 r 值引用和参数类型推导、特殊推导规则和引用折叠启动时,我们就有一个所谓的“通用引用”,这对于完美的转发功能特别有用。

每当我们有一个通用参考(a在我们的例子中)时,我们几乎总是希望在我们想要使用它们时保留其原始的“左值”或“右值”。为了有这种行为,我们几乎应该总是使用std::forward( std::forward<A>(a))。通过使用std::forward,最初作为左值传递的变量仍然是左值,而最初作为右值传递的变量仍然是右值。

之后,事情就简单了

return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }};

注意大括号的使用。它不使用括号,而是使用 C++11 调用构造函数的统一初始化语法。使用new TT{ i, std::forward<A>(a) },您可以TT在大括号内动态分配具有给定参数的类型对象。使用unique_ptr<TT>{new TT{ i, std::forward<A>(a) }};,您正在创建一个unique_ptr<TT>其参数是动态分配返回的参数。然后unique_ptr<TT>对象现在从函数返回。

于 2013-08-22T06:41:57.957 回答
1

由于模板参数推导和引用折叠规则,您无法知道a是右值引用还是左值引用。std::forward将参数传递给 TT 委托人,就像它传递给 make_unique 一样。Scott Meyers 称为A&&通用引用,因为它可以是左值引用或右值引用,具体取决于传递给 make_unique 的内容。

如果将右值传递Foomake_uniquestd::forward则传递右值引用。

如果将左值传递Foomake_uniquestd::forward则传递左值引用。

 make_unique(1, Foo());         // make_unique(int, A&&) -> rvalue ref
 Foo f;
 make_unique(1, f);             // make_unique(int, A&&&) -> make_unique(int, A&) -> lvalue ref
 make_unique(1, std::move(f));  // make_unique(int, A&&&&) -> make_unique(int, A&&) -> rvalue ref
于 2013-08-22T06:28:27.423 回答