C++ 我应该在move-ctors/assignment操作符中使用std::move还是std::forward?

C++ 我应该在move-ctors/assignment操作符中使用std::move还是std::forward?,c++,c++11,C++,C++11,除非我错了,否则这两种方法似乎都很好——是否有最佳实践理由选择其中一种而不是另一种 例如: struct A { A(){} A(const A&){ std::cout << "A(const A&)\n"; } A(A&&){ std::cout << "A(A&&)\n"; } }; struct B { B(){} B(const B& right) : x(righ

除非我错了,否则这两种方法似乎都很好——是否有最佳实践理由选择其中一种而不是另一种

例如:

struct A
{
    A(){}
    A(const A&){ std::cout << "A(const A&)\n"; }
    A(A&&){ std::cout << "A(A&&)\n"; }
};

struct B
{
    B(){}
    B(const B& right) : x(right.x){ std::cout << "B(const B&)\n"; }
    B(B&& right) : x(std::forward<A>(right.x)){ std::cout << "B(B&&)\n"; }

    A x;
};

struct C
{
    C(){}
    C(const C& right) : x(right.x){ std::cout << "C(const C&)\n"; }
    C(C&& right) : x(std::move(right.x)){ std::cout << "C(C&&)\n"; }

    A x;
};

struct D
{
    D(){}
    D(const D& right) : x(right.x){ std::cout << "D(const D&)\n"; }
    D(D&& right) : x(right.x){ std::cout << "D(D&&)\n"; }

    A x;
};

int main()
{
    std::cout << "--- B Test ---\n";
    B b1;
    B b2(std::move(b1));
    std::cout << "--- C Test ---\n";
    C c1;
    C c2(std::move(c1));
    std::cout << "--- D Test ---\n";
    D d1;
    D d2(std::move(d1));
}

问题是:这些真的是类的移动构造函数/赋值操作符吗?或者他们只是从你的眼角看出来的

struct X{
X(X&&)//移动向量#1
模板
X(T&&)//完美转发向量#2
X&运算符=(X&&);//移动赋值运算符#3
模板
X&operator=(T&);//完美转发ass.operator#4
};
在实际移动向量(#1)和移动赋值操作符(#3)中,您永远不会使用
std::forward
,因为正确评估后,您将始终移动

请注意,
std::forward
如果没有一个完美的转发模板(
T&
)。第二和第四项的情况正是如此。在这里,您永远不会使用
std::move
,因为您不知道您实际得到的是右值(A-OK)还是左值(不太多)


有关如何实际工作的解释,请参见
std::forward

你是对的,我看错了ctor。我在问题中添加了一些示例代码。@Dave:您使用的
std::forward
是错误的,因为
A
不是推导出的模板参数。它恰好与std::forward的“cast to rvalue”版本相匹配。我可能不完全理解您的措辞,但是forward(并且不会总是)不会解决与移动向量中的std::move(cast to rvalue)相同的问题?旁注:VS2010似乎(错误地?)在1不存在时接受运算符2作为移动构造函数。@Dave:是的,MSVC10错误地将模板构造函数用作复制/移动构造函数。关于第一点,是的,因为
std::forward
static\u cast
的包装器。看看发生了什么?由于使用不正确,您总是强制转换为右值。在本例中,它实际上与
std::move
所做的完全相同(这也是一个简单的包装)。@Xeo:请参见案例E,以了解在实际移动构造函数中使用
std::forward
有意义的示例。在这种情况下,使用
std::move
不起作用。
--- B Test ---
A(A&&)
B(B&&)
--- C Test ---
A(A&&)
C(C&&)
--- D Test ---
A(const A&)
D(D&&)
struct X{
  X(X&&); // move ctor #1

  template<class T>
  X(T&&); // perfect forwarding ctor #2

  X& operator=(X&&); // move assignment operator #3

  template<class T>
  X& operator=(T&&); // perfect forwarding ass. operator #4
};