【问题标题】:Confusion between std::move and std::forward [duplicate]std::move 和 std::forward 之间的混淆
【发布时间】:2018-02-19 11:57:26
【问题描述】:

因此,为了便于理解,我只是编写了std::forward 的示例和人为示例,但它并没有按我预期的方式工作。在下面的程序中

#include <string>
#include <iostream>

struct A
{
    A(const std::string& m) : m_(m) {};
    std::string m_;
};

template<typename T>
void funcB(T&& obj)  // universal reference
{
    std::string local = std::move(obj.m_);   // using std::move on universal reference. Bad.
    std::cout << "funcB : " << local << '\n';
}

template<typename T>
void funcC(T&& obj)  // universal reference
{
    std::string local = std::forward<std::string>(obj.m_);   // using std::move on universal reference
    std::cout << "funcC : " << local << '\n';
}

template<typename T>
void funcD(T&& obj)  // universal reference
{
    T local = std::forward<T>(obj);   // using std::move on universal reference
    std::cout << "funcD : " << local.m_ << '\n';
}

int main()
{
    A obj("firstString");

   //funcA(obj);  // We get compiler error. Rvalue reference cannot be bound to Lvalue
    funcB(obj);  
    std::cout << "Main : " <<  obj.m_ << '\n';

    A obj2("secondString");
    funcC(obj2);
    std::cout << "Main : " << obj2.m_ << '\n';

    A obj3("thirdString");
    funcD(obj3);
    std::cout << "Main : " << obj3.m_ << '\n';
}

在输出中

funcB : firstString
Main : 
funcC : secondString
Main : 
funcD : thirdString
Main : thirdString

funcC 中,即使我使用了通用引用并且在这里它绑定到左值,但当我执行std::forward&lt;std::string&gt; 时,字符串会被移动。因此在最后一行,在“Main:”之后没有输出。即使 obj 绑定到 Lvalue,有人可以请教如何移动字符串。

重读一本书后才意识到这个问题的答案。

在funcC中,std::forward&lt;std::string&gt;(obj.m_)相当于移动字符串。 但是在funcD中,std::forward被实例化为std::forward&lt;struct A&amp;&gt;(obj),被复制了。

【问题讨论】:

  • 顺便说一下,现在叫转发参考,而不是通用参考
  • 既然是C++17吗?
  • @avi007: Basically, yes,尽管除了标准之外,这已经是几年来的常用术语了。唯一实际的标准更改是添加这个名称(旧名称从未在其中),因此在讨论符合 C++ 以来任何标准的代码时,您可能可以安全地应用新流行的术语11.

标签: c++ c++11 stdmove


【解决方案1】:

在这两种情况下,您都在构造一个字符串std::string local,并使用右值引用作为参数。因此,local 是从该引用所引用的原始对象移动构造的。

这与std::forwardstd::move 没有太大关系;此外,您没有初始化引用(这是 Meyers 文本中“将引用绑定到左值”的来源;引用将在 LHS 上)——您只是从另一个对象构造一个对象对象。

然而,如果不写std::forwardstd::move,你最终会复制这些函数参数,因为右值引用将被丢弃在local 的初始化端的声明。

所以,在这种情况下,std::forwardstd::move 具有相同的效果。但是,它们不是一回事,通常不应被视为可互换的。阅读以下内容了解更多信息:

【讨论】:

  • 并不意味着要先入为主。但我目前正在学习有效的现代 C++。在第 5 章中,我几乎可以在任何地方看到诸如“绑定到左值”和“绑定到右值”之类的短语。funcC 中的 obj 是通用引用,我在 main 中传递了 obj2。所以它被普通引用(即左值)实例化。
  • @avi007:好吧,假设迈耶斯,我知道你从哪里得到的。这本书指的是对左值的绑定引用,即从左值初始化引用。不是相反(我认为不存在)。我已经稍微调整了我的答案以澄清。
  • 我刚刚添加了funcD,它是问题中的对应输出。您能否评论一下它与 funcC 的不同之处。
  • 刚刚经历,Effective Modern C++ 又来了。所以根据条款 28,在 funcD 中,forward 被实例化为 forward,所以输出是有意义的。感谢轨道上的轻量级比赛
猜你喜欢
  • 2016-07-08
  • 2015-05-03
  • 2016-03-21
  • 2015-02-14
  • 2023-03-18
  • 2018-07-05
  • 1970-01-01
  • 2013-06-25
  • 1970-01-01
相关资源
最近更新 更多