5

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?

Martin Drozdik
  • 12,742
  • 22
  • 81
  • 146
  • 5
    Thou shalt not inherit from std types (unless explicitly allowed to). – bitmask May 13 '13 at 12:12
  • @bitmask But I do not want polymorphic behavior or any complicated functionality. I just want to simply add the deep copy functionality. Is there a way in which this can make me sufffer? Please do you have some resources on this matter? – Martin Drozdik May 13 '13 at 12:14
  • I guess, in my case this question http://stackoverflow.com/questions/4353203/thou-shalt-not-inherit-from-stdvector applies – Martin Drozdik May 13 '13 at 12:22
  • 1
    @MartinDrozdik If `template void foo(const std::vector &arg)` does a copy of `arg` internally, it will not perform a deep copy if `Container` is passed in. – Angew is no longer proud of SO May 13 '13 at 12:34
  • 1
    [This post](http://stackoverflow.com/a/2034936/430766) also has some relevance. One may think "oh well, I'll make sure, nobody uses the type polymorphically" but the thing with software is, somebody will eventually have idea to do so, regardless how much warnings you put in documents (personally, my brain has developed a compiler-view-mode, where I don't even *see* comments when reading code, unless I'm specifically searching for them). – bitmask May 13 '13 at 18:11

1 Answers1

8

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).

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451