Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do the default generated move members do?

Tags:

c++

c++11

I want to make a container which manages big objects which performs deep copies on copy construction and copy assignment.

template <class TBigObject>
class Container : public std::vector< std::shared_ptr<TBigObject> >
{
public:
    Container(int nToAllocate){ /* fill with default constructed TBigObjects */ }
    Container(const Container& other){ /* deep copy */ }
    Container(Container&&) = default;
    Container& operator = (const Container& population){ /* deep copy */ }
    Container& operator = (Container&&) = default;
};

I would like to know what do the defaulted:

Container(Container&&) = default;
Container& operator = (Container&&) = default;

members actually do.

If I call:

Container<int> makeContainer()
{
    ...
}

and set up debugging breakpoints at:

Container<int> moveAssigned; 
moveAssigned = makeContainer(); // EDIT corrected thanks to Andy Prowl
Container<int> moveConstructed(makeContainer());

and inside the copy constructor and assignment operator, the debugger jumps over these breakpoints. So it seems that the defaulted move members actually do not perform deep copies and move all the subobjects.

Is this behavior guaranteed by the standard? Do defaulted move members behave intuitively and move all the subobjects?

like image 643
Martin Drozdik Avatar asked May 13 '13 12:05

Martin Drozdik


1 Answers

Do defaulted move members behave intuitively and move all the subobjects?

Yes. Per paragraph 12.7/15 of the C++11 Standard:

The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members. [...]

By the way, this:

Container<int> moveAssigned = makeContainer();

Is not a move assignment, but a move construction that uses copy-initialization syntax. A move assignment would be this:

Container<int> moveAssigned;
// ...
moveAssigned = makeContainer(); // <== MOVE ASSIGNMENT HERE

The difference between this:

Container<int> c(make_container());

And this:

Container<int> c = make_container();

Is that conceptually, in the second case a temporary object of type Container<int> is constructed first from the expression on the right hand side, and then c is move-constructed from this temporary.

In the first case, you have a direct initialization, meaning c will be constructed directly from the object returned by make_container().

The reason I stressed the word "conceptually" is that, in practice, compilers are allowed to perform copy elision, so the second version is likely to be optimized into the first one (although accessibility of the copy constructor or move constructor must still be checked by the compiler).

like image 147
Andy Prowl Avatar answered Sep 19 '22 14:09

Andy Prowl