5

My class A explicitly implements both its copy constructor and its copy assignment.

Which copy mechanism is used when copy assigning a vector of such elements?

Is this:

vector<A> a1, a2(5);
a1 = a2;

going to use A's copy constructor for all new elements of a1, with the elements of a2 as input?

Or is it going to make room in a1 for the elements, then use A's operator= with the elements of a2 as input?

What if a1 isn't empty before the assignment?

Is it even specified?

My class's copy constructor and operator= don't exactly do the same thing (is it bad practice? Mainly testing stuff so far). It looks like the copy constructor is called, but I wonder if it is guaranteed to be that way or if it just happens to be so in this very case.

Gauthier
  • 40,309
  • 11
  • 63
  • 97
  • 2
    Have you tried running in a debugger and setting a breakpoint in the copy-constructor or the assignment operator? Which of these breakpoints gets hit? – Some programmer dude Nov 09 '16 at 09:59
  • "It looks like the copy constructor is called", I know that because I am measuring execution time (`operator=` does deep copy, copy constructor doesn't). I'm not sure if it's guaranteed to be the case though. – Gauthier Nov 09 '16 at 10:00

2 Answers2

5

In this context it will call the copy constructor 5 times. Since a1 is empty, there aren't any elements to assign to. So they need to be copy-constructed.

Generally, it will call whatever mixture of copy/move construction/assignment or deletion is appropriate. All depending on the sizes of the vectors in question, the particular vector operation you are performing, and the value categories of the operands.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Couldn't the implementation just do a `resize` on the vector, then copy assign? – Gauthier Nov 09 '16 at 10:02
  • To your edit: that means it would be a bad idea to have copy constructor perform a deep copy, and `operator=` perform a shallow copy... right? – Gauthier Nov 09 '16 at 10:03
  • @Gauthier, 1) Default constructing objects just to assign into them immediately is against the spirit of c++ 2) That is a bad idea regardless of `std::vector`. Have you heard about the [Rule of 0/3/5](http://en.cppreference.com/w/cpp/language/rule_of_three)? – StoryTeller - Unslander Monica Nov 09 '16 at 10:06
  • I've heard about the 3 and 5, at least. And I have the three implemented, although not doing the same thing. It does feel bad though, I'll change that. – Gauthier Nov 09 '16 at 10:12
  • "...whatever mixture of copy/move construction/assignment..." - Copy-construct/assignment I can certainly see, but if there is a case where 'move' comes into play in general container assignment as presented by the OP, I'm pressed to think of what it would be (it's been a long night; brain is a little foggy). – WhozCraig Nov 09 '16 at 10:13
  • @WhozCraig, *"...depending on the sizes of the vectors in question, and their value categories."* Tried to be a bit more general than the OPs specific case – StoryTeller - Unslander Monica Nov 09 '16 at 10:14
  • @StoryTeller I read what you wrote. Doesn't change my comment. Is there a case you can think of where `std::container` assignment is forced into *move* semantics? If so, i'd love to see it. – WhozCraig Nov 09 '16 at 10:16
  • OP's question is about copy assignment; you are talking about assignment in general. – T.C. Nov 09 '16 at 10:26
  • @T.C. Yes, I clued myself in on that by using the word "Generally". I addressed the OPs particular context in my first paragraph. The second is my attempt at a broader view of the matter. – StoryTeller - Unslander Monica Nov 09 '16 at 10:27
0

It looks like the copy constructor is called, but I wonder if it is guaranteed to be that way or if it just happens to be so in this very case.

It could be guaranteed for the exception-safe swap-based implementation of assignment:

struct SomeClass
{
    SomeClass(const SomeClass& other) { ... }
    SomeClass(SomeClass&& other) { ... }

    // Copy/move construction is performed while initializing the parameter
    void operator=(SomeClass other)
    {
        this->swap(other);
    }

    void swap(SomeClass& other) { ... }
};

The disadvantage of such an implementation of assignment is that - because of its generality - it is not the most optimal one (for example, it does unnecessary job in case of self assignment).

In general, if exception safety concerns can be rules out, copy assigning to an object can be done faster than destroying it and constructing an in-place copy of the source object. Therefore, you should expect that performance-seeking implementations would perform assignment of objects through assignment rather than copy-construction of their sub-objects wherever possible.

Leon
  • 31,443
  • 4
  • 72
  • 97