使用 std::move 来防止复制

using std::move to prevent copying

我有以下代码:

#include <iostream>
#include <vector>

struct A
{
    std::vector<int> x;

    A()
    {
        std::cout << "A()" << std::endl;
    }

    A(const A&)
    {
        std::cout << "A(const A&)" << std::endl;
    }

    ~A()
    {
        std::cout << "~A()" << std::endl;
    }
};

struct B : public A
{
    std::vector<int> y;

    B()
    {
        std::cout << "B()" << std::endl;
    }

    B(const A&a)
    {
        std::cout << "B(const A&)" << std::endl;
        x = std::move(a.x);
        y.resize(x.size());
    }

    B(const A&&a)
    {
        std::cout << "B(const A&&)" << std::endl;
        x = std::move(a.x);
        y.resize(x.size());
    }
    B(const B&)
    {
        std::cout << "B(const B&)" << std::endl;
    }

    ~B()
    {
        std::cout << "~B()" << std::endl;
    }
};

A ret_a()
{
    A a;
    a.x.resize(10);
    return a;
}

int main()
{
    std::cout << "section I" << std::endl << std::endl;

    A a = ret_a();  
    B b(a);
    std::cout << "a.x.size=" << a.x.size() << std::endl;

    std::cout << std::endl << "section II" << std::endl << std::endl;

    B b2(ret_a());
    std::cout << "b.x.size=" << b.x.size() << std::endl;

    std::cout << std::endl << "section III" << std::endl << std::endl;
    return 0;
}

有输出(VS2013,发布版本)

section I

A()
A()
B(const A&)
a.x.size=10

section II

A()
A()
B(const A&&)
~A()
b.x.size=10

section III

~B()
~A()
~B()
~A()
~A()
  1. 为什么 "section I" 中的 a.x.size() 大小为 10?我认为 std::move 应该将所有数据从 a.x 移动到 y.x

  2. 为什么 "section II" 调用构造函数 A() 两次?我认为 B(const A&&) 会防止过度复制 A

更新

请参阅 http://pastebin.com/70Nmt9sT

处的固定代码
  1. T&&const T&& 不是同一类型。您几乎永远不需要 const 右值引用 - 自从您创建 const 后就无法窃取它的资源! B(const A&a) 中的 x = std::move(a.x); 复制 a.x 因为 std::move(a.x) 的 return 类型是 const vector<int>&&.
  2. 构造函数 B(const A&&) 调用 A 的默认构造函数,因为它派生自 A,并且成员初始值设定项列表不会尝试构造基础 A。这是第二次 A 调用。

Why a.x.size() within "section I" has size 10? I thought that std::move should move all data from a.x to y.x

这是因为 B(const A&& a)。由于 a 在该构造函数中是 const,因此您只能 const 访问其成员 x,并且在 vector<T> const 上调用 std::move 会导致vector<T> const&& 无法绑定到 vector 的移动构造函数(它采用 vector<T>&& 参数)。相反,它最终会调用复制构造函数,这会使源对象保持不变。

Why did "section II" call constructor A() twice? I thought that B(const A&&) would prevent excessive copying of A

第一个默认构造发生在 ret_a() 的正文中。第二个默认构造是 BA 子对象。为了避免第二个 move 成员初始值设定项列表中的 A 实例。

B(const A&&a)
: A(std::move(a))
{
    std::cout << "B(const A&&)" << std::endl;
    y.resize(x.size());
}

请注意,由于与上述相同的原因,move 实际上不会导致移动 a 的内容。此外,即使将签名修改为 B(A&& a) 也不会导致 a 的内容被移动,因为用户提供的复制构造函数和析构函数定义阻止了为 A 隐式生成移动构造函数,并且它将被复制。