Search code examples
c++vector

Why does the vector member variable inside the object clear its elements one more time?


As title.
Below is my code, and here is Minimal Reproducible Example

a.h

class B {
public:
    string n;
    B(string name) {
        this->n = name;
        cout << this->n<< " create" << endl;
    }
    ~B() {
        cout << this->n << " destory" << endl;
    }
};

class A {
public:
    vector<B> m_B;
    A():m_B(vector<B>{}) {
        cout << "class A create" << endl;
    };
    ~A() {
        cout << "class A destory" << endl;
    };
};

main.cpp

#include "a.h"
void addItem(A& _a,string n) {
    _a.m_B.emplace_back(n);
};
int main()
{
    A a;
    addItem(a, "a");
    addItem(a, "b");
    std::cout << a.m_B.size() <<"\n";
    std::cout << "Hello World!\n";
}

and terminal output is

class A create
a create
b create
a destory
2
Hello World!
class A destory
a destory
b destory

I would like to know why there is an extra sentence(a destory) in the fourth line?
At first, I thought it was due to "push_back" in addItem function,
but I get the same result when I use "emplace_back".
Thanks all.

know why there is an extra sentence(a destory) in the fourth line.


Solution

  • You forget that the vector may have to move elements when it runs out of capacity. Your vector starts empty, then allocates capacity for one entry, then runs out of capacity again and reallocates for two entries, then four, eight, and so on. After each move, the old objects are destroyed. Here is a minimal change to observe it:

    class B {
    public:
        string n;
        B(string name) {
            this->n = name;
            cout << this->n<< " create" << endl;
        }
        B(B&& o) noexcept
        : n(std::move(o.n))
        { cout << "move " << this->n << '\n'; }
      
        ~B() {
            cout << this->n << " destory" << endl;
        }
    };
    
    class A {
    public:
        vector<B> m_B;
        A():m_B(vector<B>{}) {
            cout << "class A create" << endl;
        };
        ~A() {
            cout << "class A destory" << endl;
        };
    };
    void addItem(A& _a,string n) {
        _a.m_B.emplace_back(n);
    };
    int main()
    {
        A a;
        addItem(a, "a");
        std::cout << "Capacity " << a.m_B.capacity() << '\n';
        addItem(a, "b");
        std::cout << "Capacity " << a.m_B.capacity() << '\n';
        addItem(a, "c");
        std::cout << "Capacity " << a.m_B.capacity() << '\n';
        std::cout << a.m_B.size() <<"\n";
        std::cout << "Hello World!\n";
    }
    

    Prints

    class A create
    a create
    Capacity 1
    b create
    move a
     destory
    Capacity 2
    c create
    move a
    move b
     destory
     destory
    Capacity 4
    3
    Hello World!
    class A destory
    a destory
    b destory
    c destory