我应该在移动ctors /赋值运算符中使用std :: move或std :: forward吗?

Dav*_*vid 9 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(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));
}
Run Code Online (Sandbox Code Playgroud)

输出:

--- B Test ---
A(A&&)
B(B&&)
--- C Test ---
A(A&&)
C(C&&)
--- D Test ---
A(const A&)
D(D&&)
Run Code Online (Sandbox Code Playgroud)

Xeo*_*Xeo 13

问题是:那些真的是类的移动构造函数/赋值运算符吗?或者他们只是从你的眼角看起来像那样?

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
};
Run Code Online (Sandbox Code Playgroud)

在一个真正的移动ctor(#1)和移动赋值算子(#3)中,你将永远不会使用std::forward,因为,正如你正确评估的那样,你将永远移动.

请注意,std::forward没有完美的转发模板(T&&),永远不会有意义.这正是#2和#4的情况.在这里,你永远不会使用std::move,因为你不知道你是否真的有一个右值(A-OK)或左值(不是那么多).

看到我的这个答案,解释std::forward实际上是如何工作的.

  • @Xeo:请参阅http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2951.html案例E,了解在*real*中使用`std :: forward`的示例移动构造函数有意义.在这种情况下,使用`std :: move`不起作用. (2认同)