-1

I was trying out a simple code below

#include <iostream>
#include <string>
#include <vector>
using namespace std;
class employee
{
    private:
        int emp_id;
    public:
        void getEmpid(){cout<<emp_id<<endl;}
        void setEmpid(){ cin>>emp_id;}
        employee():emp_id(10){cout<<"construct 1 "<<"employee id "<<emp_id<< endl;}
        employee(int empid):emp_id(empid){cout<<"construct 2 "<<"employee id "<<emp_id<<endl;}
        employee(const employee &emp):emp_id(emp.emp_id){cout<<"copy construct 3  "<<"employee id "<<emp_id<<endl;}
        employee(employee&& other) : emp_id(other.emp_id) {cout<<"move construct 4 "<<"employee id "<<emp_id<<endl;}
        ~employee(){cout<<"destructor"<<endl;}
};

int main()
{
    vector<employee>a;
    employee s[8]={1,2,3,4,5}; 

    for(int i=0;i<sizeof(s)/sizeof(s[0]);i++)
        a.push_back(s[i]);
    a.push_back(20);
    a.push_back(30);
    a.push_back(40);
    a.push_back(50);
    a.push_back(60);
    for(int i=0;i<a.size();i++)
        a[i].getEmpid();

    return 0;
}

*I get the below output. Not very clear how the constructors and destructors are called and in which order. could some one please throw some light? *

Output:
construct 2 employee id 1
construct 2 employee id 2
construct 2 employee id 3
construct 2 employee id 4
construct 2 employee id 5
construct 1 employee id 10
construct 1 employee id 10
construct 1 employee id 10
copy construct 3 employee id 1
copy construct 3 employee id 2
copy construct 3 employee id 1
destructor
copy construct 3 employee id 3
copy construct 3 employee id 1
copy construct 3 employee id 2
destructor
destructor
copy construct 3 employee id 4
copy construct 3 employee id 5
copy construct 3 employee id 1
copy construct 3 employee id 2
copy construct 3 employee id 3
copy construct 3 employee id 4
destructor
destructor
destructor
destructor
copy construct 3 employee id 10
copy construct 3 employee id 10
copy construct 3 employee id 10
construct 2 employee id 20
move construct 4 employee id 20
copy construct 3 employee id 1
copy construct 3 employee id 2
copy construct 3 employee id 3
copy construct 3 employee id 4
copy construct 3 employee id 5
copy construct 3 employee id 10
copy construct 3 employee id 10
copy construct 3 employee id 10
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
construct 2 employee id 30
move construct 4 employee id 30
destructor
construct 2 employee id 40
move construct 4 employee id 40
destructor
construct 2 employee id 50
move construct 4 employee id 50
destructor
construct 2 employee id 60
move construct 4 employee id 60
destructor
1
2
3
4
5
10
10
10
20
30
40
50
60
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor
destructor

Sitaram S
  • 9
  • 3
  • 2
    Welcome to StackOverflow! Maybe it would help explain what's going on if you printed out the employee ID in each of those functions. – Arthur Tacca Jul 12 '20 at 08:12
  • *Not very clear how the constructors and destructors are called and in which order* -- You should cut down your `main` program so that you get a more manageable example. You just have too many things going on in `main`. For example, the fist line that has nothing to do with `vector`, `employee s[8]={1,2,3,4,5};` generates output. – PaulMcKenzie Jul 12 '20 at 08:17
  • 1
    Why don't you try experimenting yourself? Use a debugger, set breakpoints on each of the statements involving an object of your class, see the output screen, watch your variables. Put up your part of the theory, and if you're wrong we'll be happy to correct you. – brc-dd Jul 12 '20 at 08:32
  • Sure trying it out , wasn't sure about allocation/deallocation when the capacity is full, thanks to Waqar for the answer – Sitaram S Jul 12 '20 at 11:07

1 Answers1

1

Making a little modification to your code will make the output easily understandable. Specifically, change the destructor:

   ~employee(){cout<<"destructor " << emp_id <<endl;} // shows emp_id when destructing

And change your main to give a smaller, yet similar output. I added a few couts to separate things and make it more understandable when viewing the output:

int main()
{
    vector<employee>a;
    
    std::cout << "\ncreating array of employee[3]...\n" << std::endl;
    
    employee s[3]={1,2};
    
    std::cout << "\nstarting loop, copy into vec a\n" << std::endl;

    for(int i=0;i<sizeof(s)/sizeof(s[0]);i++) {
        cout << "Vec size now: " << a.size() << " Capacity: " << a.capacity() << endl;
        a.push_back(s[i]);
    }

    cout << "Outside, Vec size now: " << a.size() << " Capacity: " << a.capacity() << endl;
    
    std::cout << "\ndoing push back outside loop\n" << std::endl;
        
    a.push_back(20);
    a.push_back(30);
    
    std::cout << "\nAll done exiting...\n" << std::endl;

     //removed this, since we are only talking about ctors / dtors
     //reduces noise
    // for(int i=0;i<a.size();i++)
    //     a[i].getEmpid();

    return 0;
}

The output that I got was following, I will split it and explain:

Some definitions regarding vector:

  • Capacity: the number of elements that can be held in currently allocated storage
  • Size: the number of elements in vector

Code: employee s[3]={1,2};

Output:

creating array of employee[3]...

construct 2 employee id 1
construct 2 employee id 2
construct 1 employee id 10

Three constructors are called, 2 employee(int) and 1 default. The first two elements of array call the employee(int). The 3rd element is default constructed.

Code:

    for(int i=0;i<sizeof(s)/sizeof(s[0]);i++) {
        cout << "Vec size now: " << a.size() << " Capacity: " << a.capacity() << endl;
        a.push_back(s[i]);
    }

Output:

starting loop, copy into vec a

//iteration 1
Vec size now: 0 Capacity: 0 //vec is zero initially
copy construct 3  employee id 1 //id 1 is copy constructed and pushed back

//iteration 2
Vec size now: 1  Capacity: 1  //vec is now size: 1, with 1 element
//we are doing a push back, but the size needs to grow. Vector reallocates and size becomes 2. The previous memory and the elements in that memory are deallocated/destructed.

copy construct 3  employee id 2 //push back(), copy contruct into vector
copy construct 3  employee id 1 // since we reallocated, the previous memory is gone,
                                //we need to add the previous element as well
destructor 1                    //previous element, id: 1, now being destructed.

//iteration 3
//follows the same logic as in iteration 2. size by the end will be 3 (3 elements). Capacity will be 4. That means we can do one more push back without destroying everything and reallocating.

Vec size now: 2  Capacity: 2
copy construct 3  employee id 10
copy construct 3  employee id 1
copy construct 3  employee id 2
destructor 1
destructor 2

Outside, Vec size now: 3 Capacity: 4                                                                                                    

Code:

    a.push_back(20);
    a.push_back(30);

Output:

doing push back outside loop
//remember we have capacity 4

construct 2 employee id 20     //construct id 20
move construct 4 employee id 20 //move into push_back() (because 20 is temporary, rvalue)
destructor 20                   //destroy what we constructed

//capacity: 4, size: 4

construct 2 employee id 30      // construct id 30
move construct 4 employee id 30 //move into push_back()
//uh oh.. capacity was full, deallocations, destructions, reconstructions:
copy construct 3  employee id 1
copy construct 3  employee id 2
copy construct 3  employee id 10
copy construct 3  employee id 20
destructor 1
destructor 2
destructor 10
destructor 20
destructor 30 //destroy our temporary id: 30

All done, now just the destructors for all the elements will be called one by one.

All done exiting...

destructor 10
destructor 2
destructor 1
destructor 1
destructor 2
destructor 10
destructor 20
destructor 30

Lesson: Use reserve() whenever you can.

Moreover, look into vector::clear(), vector::shrink_to_fit, see what it does. Read the docs for additional info.

Waqar
  • 8,558
  • 4
  • 35
  • 43