Strange vector behaviour

Sep 11, 2018 at 1:00pm
I don't understand why I see lines marked with arrows in console. I added c1 and c2 to vector with std::move. But when I was adding c3 and c4, I got extra copy constructor calling for c1 and for c1 and c2. WHY?!

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
c1: meow!
c2: meow!
c3: meow!
c4: meow!
c1: !!!!
c2: !!!!
c1: ???? // <====
c3: ????
c1: ???? // <====
c2: ???? // <====
c4: ????
c1: say meow again
c2: say meow again
c3: say meow again
c4: say meow again


Source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <string>
#include <vector>

class Cat {
public:
    Cat(std::string name) : myName(name) {
        std::cout << myName << ": meow!" << std::endl;
    }
    
    Cat(const Cat& other) {
        myName = other.myName;
        std::cout << myName << ": ????" << std::endl;
    }
    
    Cat(const Cat&& other) {
        myName = other.myName;
        std::cout << myName << ": !!!!" << std::endl;
    }
    
    void say() {
        std::cout << myName << ": say meow again" << std::endl;
    }
private:
    std::string myName;
};

int main()
{
    Cat c1("c1");
    Cat c2("c2");
    Cat c3("c3");
    Cat c4("c4");
    
    std::vector<Cat> cats;
    
    cats.push_back(std::move(c1));
    cats.push_back(std::move(c2));
    cats.push_back(c3);
    cats.push_back(c4);
    
    for (Cat & c : cats)
        c.say();
        
    return 0;
}
Last edited on Sep 11, 2018 at 1:09pm
Sep 11, 2018 at 1:09pm
The vector is being resized. With the resizing, it is copied.

Allocate enough space to the vector to begin with and the resizing will no longer be necessary:

cats.reserve(10);, for example.
Sep 11, 2018 at 1:41pm
> But when I was adding c3 and c4, I got extra copy constructor calling for c1 and for c1 and c2. WHY?!

The move constructor for Cat is not declared as noexcept So the vector implementation is helpless; it can't safely move the objects from one buffer to another; it has to copy them.

See the notes for std::move_if_noexcept: https://en.cppreference.com/w/cpp/utility/move_if_noexcept

With a non throwing move constructor, we would see the expected behaviour:
http://coliru.stacked-crooked.com/a/aea6d327cdfe3c46
Last edited on Sep 11, 2018 at 1:42pm
Topic archived. No new replies allowed.