GregK1
GregK1

Reputation: 21

vector and push_back()

#include <iostream>
#include <vector>
#include <algorithm>

class my {
  public:
    my() {
      counter++;
      std::cout << "class constructor" << counter << " \n";}

    ~my() {
      std::cout << "class destructor" << counter << " \n";
      counter--;
    }
  
    static inline int counter = 0;
};

int main()
{
    my v1;
    std::vector<my> my_vec;

    my * p = new my();
    my_vec.push_back(std::move(*p));
    my_vec.push_back(std::move(v1));
}

simply example, however I do not understand what I am doing wrong, in result I get 2 extra destructor called than I expect (expect 2). Could some one explain it?

results:

class constructor1
class constructor2
class destructor2
class destructor1
class destructor0
class destructor-1

Upvotes: 2

Views: 148

Answers (2)

Milind Deore
Milind Deore

Reputation: 3063

Please see inline ...

#include <iostream>
#include <vector>

class my {
  public:
    my() {
      counter++;
      std::cout << "class constructor" << counter << " \n";
      std::cout << "Object Address : " << this << std::endl;
    }


    ~my() {
      std::cout << "class destructor" << counter << " \n";
      std::cout << "Object Address : " << this << std::endl;
      counter--;
    }

    static inline int counter = 0;
};

int main()
{
    my v1;     /* 1. Object on stack (constructor called) */
    std::vector<my> my_vec;

    my * p = new my();   /* 2. Object created on heap (constructor called) */
    my_vec.push_back(std::move(*p));
    my_vec.push_back(std::move(v1));
}

Output is:

class constructor 1 Address : 0x7ffee1488760
class constructor 2 Address : 0x7f9f47400350
class destructor 2 Address : 0x7f9f474026e0
class destructor 1 Address : 0x7f9f474026f1
class destructor 0 Address : 0x7f9f474026f0
class destructor -1 Address : 0x7ffee1488760

Object on the stack called destructor as soon as it goes out of the scope i.e. Scope of the object on stack is limited to the code block. In this case block end when main exits.

But the object on heap (new) is a potential leak, had this being inside while loop would have consumed memory and eventually crashed. For each new you need to explicitly called delete, which means you have to call its destructor. Thanks to stack it does that for us but not heap, and c++ also doesn't have garbage collector.

std::move is a copy operation and hence no constructor is called. details here.

Upvotes: 1

Erlkoenig
Erlkoenig

Reputation: 2754

Analyzing the program step-by-step:

my v1;

One Instance is created, constructor is called.

my * p = new my();

Another instance is created, constructor is called.

my_vec.push_back(std::move(*p));

A copy of the second instance is inserted into the vector; the implicitly defined move-constructor is called (which just copies; no output is printed).

my_vec.push_back(std::move(v1));

The vector allocates new storage for 2 instances, copies the previously stored instance into the new storage (invoking the implicitly defined move-constructor, which just does copying, still no output for this), and invokes the destructor for the instance in the old storage (so first destructor output is printed).

Then, the vector goes out of scope, so its two contained elements get destroyed (so, 2 destructor calls). Then, v1 goes out of scope, printing the 4th destructor call. The instance p is leaked, i.e. never destroyed (memory leak).

Upvotes: 3

Related Questions