使用std :: move来防止复制

时间:2015-02-20 06:58:27

标签: c++ c++11 move-semantics

我有以下代码:

#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. 为什么a.x.size()在&#34;部分I&#34;大小10?我认为std :: move应该将所有数据从a.x移动到y.x

  2. 为什么&#34;第二节&#34;调用构造函数A()两次?我认为B(const A&amp;&amp;)会阻止过度复制A

  3. 更新

    查看http://pastebin.com/70Nmt9sT

    处的固定代码

2 个答案:

答案 0 :(得分:4)

  1. T&&const T&&的类型不同。您几乎从不想要const右值引用 - 自从您创建const之后就无法窃取其资源!由于std::move(a.x)的返回类型为x = std::move(a.x);B(const A&a) a.x const vector<int>&& B(const A&&) {/ 1}}。
  2. 构造函数A调用A的默认构造函数,因为它是从A派生的,并且成员初始值设定项列表不会尝试构造基础A }。这是第二次{{1}}电话。

答案 1 :(得分:2)

  

为什么a.x.size()在&#34;部分I&#34;大小10?我认为std::move应该将所有数据从a.x移到y.x

这是因为B(const A&& a)。由于该a const位于该构造函数中,因此您只有const个成员x的访问权限,而std::move上的vector<T> const调用结果为vector<T> const&&一个vector,它无法绑定到vector<T>&&的移动构造函数(带有A()参数)。相反,它最终会调用复制构造函数,这会使源对象保持不变。

  

为什么&#34;第二节&#34;调用构造函数B(const A&&)两次?我认为A可以防止过度复制ret_a()

第一个默认构造发生在A的主体内。第二个默认构造是B 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的内容,因为用户提供的复制构造函数和析构函数定义会阻止隐式生成{{1}}的移动构造函数,并且它会被复制。