4

I'm a bit confused as to how destructors are called on objects constructed through vector, but only once when I create object using pointer.

#include <iostream>
#include <vector>
#include <string>

class Student
{
    std::string first;
    std::string last;
    int age;

public:
    Student();
    Student(std::string f, std::string l, int a) : first(f), last(l), age(a)
    {
    };
    ~Student()
    {
        cout << "Destructor\n";
    }
};

int main()
{
    std::vector<Student> Univ;
    Univ.push_back(Student("fn1", "ln1", 1));
    Univ.push_back(Student("fn2", "ln2", 2));
    Univ.push_back(Student("fn3", "ln3", 3));
    return 0;
}

When I push back one time, I get 2 calls to destructor. 2 push backs, I get 5 calls to destructor. 3 push backs, I get 9 calls to destructor.

Normally if I do something like this,

Student * Univ = new Student("fn1", "ln1", 1);
delete Univ;

I get just one call to destructor.

Why is this?

hello
  • 1,168
  • 4
  • 24
  • 59
  • 4
    Probably the vector ran out of space, got more space elsewhere and copied or moved the Students over to the new space. Then the destructor was called for the Students in the old space. – nwp May 28 '15 at 15:20
  • @nwp In a larger program with substantial push backs, will this be a drawback? – hello May 28 '15 at 15:48
  • 1
    It cannot be avoided, unless you know the size in advance. But resizing only happens rarely so don't worry about it too much. If you can guess the size you can use vector.reserve(size). Lists do not have that problem, but they have other worse problems. In C++11 you can reduce the overhead a lot with move semantics. If the objects are very expensive to copy/move you can use pointers to objects instead. That will minimize the resizing cost but add an accessing cost and make things less convenient. – nwp May 28 '15 at 19:15

3 Answers3

2

You are creating a temporary Student which you pass to push_back, which copies it into the vector. The upshot is that you use two copies of each Student instance, and the destructor of each is called. Additionally, when you add more Students and the vector resizes, the existing contents are copied to the newly allocated memory, resulting in even more destructor calls.

If you have C++11 features available you may want to look into move semantics.

Community
  • 1
  • 1
rds504
  • 146
  • 6
1

when you do push_back and the vector don't have enough memory to store the new elements it has to resize, each time the vector resize it calls the destructor of the old elements. Try this:

std::vector<Student> Univ(3);
Univ.push_back(Student("fn1", "ln1", 1));
Univ.push_back(Student("fn2", "ln2", 2));
Univ.push_back(Student("fn3", "ln3", 3));

Besides that, you are creating temporary objects to pass to push_back, that's why the extra destructor calls.

dlavila
  • 1,204
  • 11
  • 25
1

When I push back one time, I get 2 calls to destructor. 2 push backs, I get 5 calls to destructor. 3 push backs, I get 9 calls to destructor.

Before C++11, when you push back an object to a std::vector system copy the object to the container. So if you do one push back system created 2 objects, so system has to call 2 times destructor to clean up.

Since C++11, if you define move copy constructor for your calls, std::vector use move semantics in place of copy constructor and move the object to vector instead copy the object. So system will generate only one destructor call. Following link will give you better idea http://en.cppreference.com/w/cpp/language/rule_of_three

Steephen
  • 14,645
  • 7
  • 40
  • 47