【问题标题】:C++: move / forwarding / rvalue delegation shenanigans [duplicate]C ++:移动/转发/右值委托恶作剧[重复]
【发布时间】:2015-11-18 12:03:38
【问题描述】:

尝试运行这个测试程序:

#include <iostream>

class A {
public:
    A()                          { std::cout << "empty constructor" << std::endl; }
    A(const A &a)                { std::cout << "copy constructor" << std::endl; }
    A(A &&a)                     { std::cout << "move constructor" << std::endl;  }
    ~A()                         { std::cout << "destructor" << std::endl; }
    A &operator=(const A &o)     { std::cout << "copy assignment" << std::endl; return *this; }
    A &operator=(A &&o)          { std::cout << "move assignment" << std::endl; return *this; }
};

A outside;

template <typename U>
void bar(U &&a) {
    outside = std::forward<U>(a);
}

void foo(A &&a) {
    bar(a);
}

int main(int argc, char *argv[]) {
    foo(A());
    return 0;
}

在我的编译器上,我认为是 GCC 4.4.1,输出是:

empty constructor
empty constructor
copy assignment // what??
destructor
destructor

在我看来,第三行很奇怪。为什么outsidebar 中复制a 而不是移动它?换句话说,为什么foo 使用bar(A &amp;a) 实例化bar 而不是bar(A &amp;&amp;a)

我应该提到,通过将foo 更改为

,可以轻松解决此问题
template <typename U>
void foo(U &&a) {
    bar(std::forward<U>(a));
}

因此使用移动赋值运算符。

在我的代码中,我有很多委托方法,我不想将它们全部放在一个 .h 文件中并为它们制作模板。是否有另一种方式告诉编译器或使其了解afoo 中用作右值?

编辑:一些人指出了这一变化:

void foo(U &&a) {
    bar(std::move(a));
}

我太慢了,无法表明我希望foo 能够接受两者:

int main(int argc, char *argv[]) {
    foo(A());
    return 0;
}

int main(int argc, char *argv[]) {
    A a;
    foo(a);
    return 0;
}

在第二种情况下,建议的代码将错误地窃取amain 中的资源,应将其用作参考。

【问题讨论】:

  • 因为a in foo 是一个左值。你需要bar(std::move(a));。我正在寻找一个好的副本。
  • 我已编辑问题以更清楚地解释问题。谢谢!
  • @bombax:真的没有别的办法。如果您想要一个转发的方法,那么您需要复制该方法或对其进行模板化。
  • 如果还不清楚:即使你写了foo( (A&amp;&amp;)a )(这是你的g++版本正在做的),那么foo没有关于它是否被调用的信息临时对象与否;您必须复制 (bar(a)) 或窃取资源 (bar(std::move(a)))。仅从右值(不使用模板)窃取的正确方法是有一对重载void foo(A&amp; a) { bar(a); } void foo(A&amp;&amp; a) { bar(std::move(a)); }
  • 重载对的替代方案是template&lt;typename T&gt; void foo(T &amp;&amp;a) { bar(std::forward(a)); },因为转发引用可以推导出引用类型;但我猜你没有这样做,因为你本来可以打电话给bar :)

标签: c++ move semantics


【解决方案1】:

在你的 foo 函数中它应该是: bar(std::move(a)) 因为参数a 在那个时候是一个左值。

【讨论】:

  • 我已经编辑了问题以更清楚地说明我想要什么,谢谢!
猜你喜欢
  • 1970-01-01
  • 2010-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-26
  • 2011-07-31
相关资源
最近更新 更多