在移动构造函数/赋值运算符中,我应该使用std::move还是std::forward?

9

除非我错了,似乎两者都可以正常工作 - 是否有最佳实践理由更喜欢其中之一?

示例:

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));
}

输出:

--- B Test ---
A(A&&)
B(B&&)
--- C Test ---
A(A&&)
C(C&&)
--- D Test ---
A(const A&)
D(D&&)
1个回答

14
问题是:那些是否真的是该类的移动构造函数/赋值运算符?或者它们只是从你眼角的角度看起来像那样?
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
};

在实现移动构造函数(#1)和移动赋值运算符(#3)时,您永远不会使用std::forward,因为如您所正确评估的那样,您总是会进行移动。
请注意,没有完美转发模板(T&&)时,std::forward从来没有意义。这正是#2和#4的情况。在这里,您永远不会使用std::move,因为您不知道您是否真的得到了一个右值(没问题)还是左值(不太好)。
有关std::forward实际工作原理的说明,请参见我提供的这个答案

你说得对,我看错了构造函数。我在问题中添加了一些示例代码。 - David
@Dave:你使用 std::forward 是错误的,因为 A 不是一个推导的模板参数。它只是恰好匹配了 std::forward 的“转换为右值”的版本。 - Xeo
我可能没有完全理解你的措辞,但是在移动构造函数中,forward(并且它不总是)不会解析为与std :: move相同的内容吗(转换为右值)?顺便说一句:当#1不存在时,VS2010似乎(错误地?)将您的operator#2视为移动构造函数。 - David
2
@Xeo:请参考http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2951.html案例E,其中使用`std::forward`在*真实的*移动构造函数中是有意义的。在这种情况下,使用`std::move`是行不通的。 - Howard Hinnant
我现在想起来了,有更多情况下我会在移动构造函数和移动赋值运算符中使用std::forward而不是std::move:只要我的数据成员可以是引用类型。这种情况发生在pairunique_ptr中。 - Howard Hinnant
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接