简体   繁体   中英

using std::move to prevent copying

I have the following code:

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

With output (VS2013, Release build)

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. Why axsize() within "section I" has size 10? I thought that std::move should move all data from ax to yx

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

UPDATE

see fixed code at http://pastebin.com/70Nmt9sT

  1. T&& and const T&& are not the same type. You almost never want a const rvalue reference - you can't steal its resources since you made it const ! x = std::move(ax); in B(const A&a) copies ax since the return type of std::move(ax) is const vector<int>&& .
  2. The constructor, B(const A&&) calls the default constructor of A since it is derived from A , and the member initializer list does not make an attempt to construct the base A . This is the second A call.

Why axsize() within "section I" has size 10? I thought that std::move should move all data from ax to yx

This is because of B(const A&& a) . Since a is const within that constructor, you only have const access to its member x , and calling std::move on a vector<T> const results in a vector<T> const&& which cannot bind to vector 's move constructor (which takes a vector<T>&& argument). Instead it ends up calling the copy constructor, which leaves the source object unmodified.

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

The first default construction occurs within the body of ret_a() . The second default construction is that of the A sub-object of B . To avoid the second one move the A instance in the member initializer list.

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

Note that the move doesn't actually result in moving the contents of a due to the same reason as explained above. Moreover, even modifying the signature to B(A&& a) would not result in the contents of a being moved because the user provided copy constructor and destructor definitions prevent implicit generation of a move constructor for A , and it'll be copied instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM