4

I'm studying C++11 and I don't understand why in the following code

class X
{
    std::vector<double> data;
public:
    // Constructor1
    X():
        data(100000) // lots of data
    {}

    // Constructor2
    X(X const& other): // copy constructor
        data(other.data)   // duplicate all that data
    {}

    // Constructor3
    X(X&& other):  // move constructor
        data(std::move(other.data)) // move the data: no copies
    {}

    X& operator=(X const& other) // copy-assignment
    {
        data=other.data; // copy all the data
        return *this;
    }

    X& operator=(X && other) // move-assignment
    {
        data=std::move(other.data); // move the data: no copies
        return *this;
    }

};

X make_x() // build an X with some data
{
    X myNewObject; // Constructor1 gets called here
    // fill data..
    return myNewObject; // Constructor3 gets called here
}


int main()
{
    X x1;
    X x2(x1); // copy
    X x3(std::move(x1)); // move: x1 no longer has any data

    x1=make_x(); // return value is an rvalue, so move rather than copy
}

in the line

return myNewObject; // Constructor3 gets called here

the Constructor3 gets called. Why?

4

2 回答 2

3

You see a move construction because your compiler is not doing all the optimization that it is permitted to by the standard.

Nominally, the variable myNewObject is move-constructed to the temporary that is the return value of make_x, and then the temporary is move-assigned to x1. This is what you're seeing.

However, in this case the standard permits something called "move constructor elision". It's basically the same thing as "copy constructor elision", which might be familiar to you from C++03. It means that the variable myNewObject and the temporary that is the return value of make_x can be transformed by the compiler into a single object. That leaves just the move assignment.

Apparently your compiler has not done the move elision.

If you expected a copy, then the reason it's a move is that in C++11, a return value that is eligible for copy elision (which this one is), is explicitly required to be moved rather than copied where a move is available. I can't remember the reference, and don't have the standard on hand, so you'll just have to take my word for it.

于 2013-03-30T13:18:53.680 回答
1
X make_x() // build an X with some data
{
    X myNewObject; // Constructor1 gets called here
    // fill data..
    return myNewObject; // Constructor3 gets called here
}

myNewObject gets destroyed at the end of this function scope, so its ok for the compiler to rip its guts out with a move.

于 2013-03-30T12:31:38.320 回答