Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vector and push_back() behavior

Tags:

c++

I'm studying to understand class constructor and destructor. I have written a small console code to add one class instance in to a vector. All is nice and dandy, but what I fail to understand is, that adding one Object in to the vector triggers destructor twice. Why does this happen?

If I don't add any object, the vector doesn't trigger constructor or destructor on its own, so why it happens twice?

Can anyone explain why this happens?

#include <cstdio>
#include <vector>
class Test
{
    private:
        int value;

    public:
        Test()
        {
            printf("\nClass constructor triggered.");
        };
        ~Test()
        {
            printf("\nClass desctructor triggered.");
        }
};

int main()
{
    std::vector<Test> container;

    container.push_back( Test() );
    return 0;
}

UPDATE: I added some more information to the class so that I get more specific output, however now I noticed that with each addition to the vector the move-construction and destructor calls increase. Are the amount of these calls tied to the amount of objects within the vector or what is happening? Am I having a leak? Sorry if too stupid questions. Below is the added code:

#include <cstdio>
#include <vector>

class Test
{
    private:
        int value;

    public:
        // Constructor
        Test(int v=0)
        {
            value = v;
            printf("\n\n%i", value);
            printf("\nClass constructor triggered.");
        };

        // Copy-move constructor
        Test(Test&&)
        {
            printf("\nClass move-constructor triggered.");
        };

        // Destructor
        ~Test() 
        {
            value = 0;
            printf("\nClass desctructor triggered.");
        }
};

int main()
{
    std::vector<Test> container;

    container.push_back( Test(1) );
    container.push_back( Test(2) );
    container.push_back( Test(3) );
    container.push_back( Test(4) );

    printf("\n\nPushback complete!");
    return 0;
}
like image 708
Mikko-Pentti Einari Eronen Avatar asked Jun 24 '26 13:06

Mikko-Pentti Einari Eronen


2 Answers

Your vector contains a copy of the object you add to it through push_back(). The first destructor invocation is caused by the temporary you create being destroyed at the end of the full expression containing the call to push_back(). The second destructor is caused by the copy inside the vector being destroyed when the vector itself is destroyed.

You can convince yourself by adding a diagnostic to main():

int main()
{
    std::vector<Test> container;

    container.push_back( Test() );

    printf("\nThis is before the vector is destroyed...");

    return 0;
}

You can observe the output in this live example.

The copy which your vector contains is created by invoking the automatically-generated move constructor for your class (rather than using default construction), which is why you don't see a corresponding construction diagnostic.

If you defined your own move constructor (or copy constructor, as shown below) to emit a diagnostic, the output would be closer to what you'd expect:

    Test(Test const&)
    {
        printf("\nCopy construction triggered.");
    };

Again, live example.

like image 187
Andy Prowl Avatar answered Jun 26 '26 04:06

Andy Prowl


Because you don't print every constructor invocation, you're missing out on move-constructor call. Your class, apart from the default constructor you've provided, has also implicitly generated move and copy constructors.

The vector stores a value, and that value has to be initialized in some way. Typically, this happens either via a move c-tor or copy c-tor, altough an object might also be created directly inside of the vector using e.g. emplace_back.

Try adding this:

Test(Test&&)
{
    printf("\nClass move constructor triggered.");
};

to your class, it should change the output to something that makes more sense (I've also added a print at the end of main):

Live On Coliru

Class constructor triggered.
Class moveconstructor triggered.
Class desctructor triggered.
Out of main scope.
Class desctructor triggered.

The first destructor call destroys moved-out "empty" instance of your class, while the second one fires when the vector itself is destroyed.

like image 44
Bartek Banachewicz Avatar answered Jun 26 '26 04:06

Bartek Banachewicz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!