【问题标题】:std::move Vs std::forwardstd::move 与 std::forward
【发布时间】:2016-07-08 15:06:58
【问题描述】:

这似乎是已经问过的最相关的问题。

Whats the difference between std::move and std::forward

但是每个答案都是不同的,适用的并且说的东西略有不同。所以我很困惑。

我有以下情况。

  • 将项目复制到容器中
    Copy 项是 C++03,所以我理解得很好。
  • 将项目构造到容器中
    我认为将 Construct item into container 正确地使用了完美转发,通过两个函数将参数转发到 emplaceBackInternal() 中的 T 的构造函数(如果我错了,请另说)。
  • 将项目移动到容器中
    我的问题似乎是理解将项目移动到容器中。

代码:

template<typename T>
class Container
{
    std::size_t length;
    T*          buffer;

public:
    void push_back(T const& value)
    {
         resizeIfRequired();
         pushBackInternal(value);
    }
    template<typename... Args>
    void emplace_back(Args&&... args)
    {
         resizeIfRequired();
         emplaceBackInternal(std::forward<T>(arg)...);
    }
    void push_back(T&& value)
    {
         resizeIfRequired();
         // Is this forward correct or should it be move
         moveBackInternal(std::forward<T>(value));
    }
private:
    void pushBackInternal(T const& value)
    {
         // Copy construct object into buffer;
         new (buffer + length) T(value);
         ++length;
    }
    template<typename... Args)
    void emplaceBackInternal(Args&&... args)
    {
         // Construct object into buffer using arguments;
         new (buffer + length) T(std::forward<T>(args)...);
         ++length;
    }
    void moveBackInternal(T&& value)
    {
         // Move construct object into buffer;
         // Is this forward correct or should it be move
         new (buffer + length) T(std::forward<T>(value));
         ++length;
    }
};

我在这里包含所有三个函数,以将这三个函数与前面提到的答案中提供的答案进行比较。主要原因是moveconstruct长得很像,感觉应该是一样的。

Answer @Potatoswatter Score 67

std::forward 有一个用例:强制转换 模板函数参数

根据这个定义,我应该在 push_back(T&amp;&amp; value) 内使用 std::movemoveBackInternal(T&amp;&amp; value) 因为该值不是函数的模板参数。

Answer @Howard Hinnant Score 38

如果 Y 是左值引用,则结果将是左值表达式。 如果 Y 不是左值引用,则结果将是右值(准确地说是 x 值)表达式。

按照这个定义,我可以使用std::movestd::forward

Answer @Bo Persson Score 11

std::forward 用于将参数完全按照传递给函数的方式转发。

似乎说std::forward 是可以接受的(尽管如果我点击答案中的链接,所有示例都使用模板函数)。

【问题讨论】:

  • 呃...链接的答案没有回答您的什么问题?
  • 呃...哪个答案是正确的!。每个都指定不同的结果。
  • 他们都是正确的。两个只是说std::forward 的目的是转发引用,第三个还花一些时间解释std::forward 是什么。

标签: c++ c++11 move perfect-forwarding


【解决方案1】:

在这种情况下:

void push_back(T&& value)
{
     resizeIfRequired();
     moveBackInternal(std::forward<T>(value));  // (1)             
     moveBackInternal(std::move(value));        // (2) 

}

std::forward&lt;T&gt;(value)std::move(value) 在这种情况下相同(1)(2) 之间没有关系...所以使用 (2))。

move 是无条件转换为 xvalue。那行给你一个T&amp;&amp; 类型的表达式,它总是一个右值。

forward 是一个条件转换。如果T 是一个左值引用类型,它会产生一个左值。否则(如果它不是引用类型或右值引用类型),它会产生一个右值。在我们的例子中,T 不是引用类型 - 所以我们得到一个右值。

无论哪种方式,我们最终都在同一点上 - 我们调用 moveBackInternal 并将 value 转换为右值。只是move() 是到达那里的一种更简单的方式。 forward&lt;T&gt; 有效,但没必要。

【讨论】:

  • 有时像这样,我希望我和您(或帖子的作者)在办公室,并且可以就更好的技术与白板进行坦率的讨论。 -- 如果我假设std::movestd::forward 所做的所有工作都是编译时工作。那么解决方案(1)不是更好,因为它使代码看起来与emplace_back() 相同。当我可以拥有一种适用于所有情况的技术时,为什么我需要两种不同的技术?更少的差异意味着更容易维护代码?
  • @LokiAstari 似乎主要基于意见。我发现当我们无条件移动时使用move() 更直接。 push_back() 代码永远不会移动,那么为什么要使用更复杂的演员表呢?最终,我发现有些东西从根本上...关闭...与转发参考。我不知道如何才能做得更好 - 无论好坏,这就是我们得到的。
  • 感谢您的所有意见。老实说,我仍在努力形成自己的观点,只是想在这里扮演魔鬼的拥护者。 :-)
猜你喜欢
  • 2015-05-03
  • 2016-03-21
  • 1970-01-01
  • 2018-07-05
  • 2013-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多