Creation of Vector array calling destructor in c++

144 Views Asked by At
#include<iostream>
#include<vector>
class Students
{
    int *arr_roll;
public:
    Students (size_t a){
        arr_roll = new int(a);
    }
    ~Students(){
        std::cout<<"Destructor called"<<std::endl;
        //delete arr_roll;
    }
    int & operator [] (size_t t){
        return arr_roll[t];
    }
};

int main(){
    std::vector<Students> School(10,5);
    School[0][1] = 2;
    std::cout<< "School[0][1]: " << School[0][1]<<std::endl;
    return 0;
}

I have a code like above and I am compiling it with gcc 9.5.0 . The output I am getting is as follows

**Destructor called**
School[0][1]: 2
Destructor called
Destructor called
Destructor called
Destructor called
Destructor called
Destructor called
Destructor called
Destructor called
Destructor called
Destructor called

Can anybody please explain why the destructor is being called during the creation of the vector (The 1st print ** marked)

3

There are 3 best solutions below

3
user12002570 On

The statement

std::vector<Students> School(10,5);

first creates an object of type Students using the parameterized ctor Students(size_t) and then uses the implicitly generated copy constructor Students(const Students&) to create 10 copies of that object. So there are total 11 objects constructed(1 using parameterized ctor and other using copy ctor). Then at the time of School's destruction, all elements are destructed using the destructor and we get the destructor called output.

This all happens because the ctor (3) given at std::vector is used here:

vector( size_type count,
                const T& value,
                const Allocator& alloc = Allocator() );  (3) since c++11
  1. Constructs the container with count copies of elements with value value.

You can verify this by adding a user defined copy ctor as done in this demo.


Note that first the parameterized ctor Students(size_t) is implicitly used to create an object of Students type and then the copy ctor is used to create 10 copies.

3
463035818_is_not_an_ai On

Your code has a couple of issues unrelated to the additional output of the constructor your are asking about. Most issues removed, it boils down to this:

#include<iostream>
#include<vector>

struct Students
{
    Students (size_t a){
    }
    ~Students(){
        std::cout<<"Destructor called"<<std::endl;
    }
};

void foo(const Students&) {}

int main(){
    foo(5); // 5 is implicitly converted to a Students instace
            // that instance is destroyed at the end of the expression
}

Output is:

Destructor called

In your case it is the call std::vector<Students> School(10,5); that constructs a temporary Students instance.

The big issue in your code is not to follow the rule of three. You shouldnt use raw new. Your constructor allocates a single integer, then School[0][1] accesses memory out of bounds. If you fix the constructor to allocate an array, then //delete arr_roll; in the destructor is wrong. Use std::vector or std::array to manage arrays for you.

0
Marek R On

Here:

std::vector<Students> School(10,5);

You are invoking this overload of std::vector constructor:
std::vector<T,Allocator>::vector - cppreference.com

vector( size_type count,  
                 const T& value,  
                 const Allocator& alloc = Allocator() );

Since for value you've feed is 5 compiler performs implicit conversion to Students using your constructor:

Students (size_t a)

So temporary automated object of type Students is created to pass it as argument value for std::vector.

After vector creation completes temporary object is destroyed.

You can:

  • add explicit keyword to your constructor to prevent implicit conversions.
  • use emplace_back to construct values directly inside a vector (loop is needed):
std::vector<Students> School;
School.reserve(10);
for (int i = 0; i<10; ++i) {
    School.emplace_back(5);
}