Be careful with hidden cost of std::vector for user defined objects

std::vector for user defined objects

While using std::vector with user defined classes we have to take special care or performance of our application otherwise performance will be hampered.

E.g. let we have a Branch class. And then create 500 item objects by creating a Student class for it. After creating 1000 objects of class Student, but while creating many objects are wasted.

Example program 1 :

#include <iostream>
#include <vector>
class Student {
public:
    static int contructorCalledTemp;
    static int destiCalledTemp;
    static int copyconstructorCalledTemp;
    Student()     {
        contructorCalledTemp++;
    }
    ~Student()    {
        destiCalledTemp++;
    }
    Student(const Student& obj) {
        copyconstructorCalledTemp++;
    }
};
int Student::contructorCalledTemp = 0;
int Student::copyconstructorCalledTemp = 0;
int Student::destiCalledTemp = 0;

class Branch
{
public:
    static std::vector<Student> getStudentObjects(int temp)
    {
        std::vector<Student> vectStudents;
        vectStudents.reserve(temp);
        for (int i = 0; i < temp; ++i) {
            vectStudents.push_back(Student());
        }
        return vectStudents;
    }
};

int main()
{
    int temp = 1000;
    std::vector<Student> vectStudents;
    vectStudents = Branch::getStudentObjects(temp);    std::cout<<"Total no. of Student objects created : "<<(Student::contructorCalledTemp + Student::contructorCalledTemp)<<std::endl;
    std::cout<<"Constructor was called  "<<Student::contructorCalledTemp <<" times"<<std::endl;
    std::cout<<"Copy Constructor was called  "<<Student::copyconstructorCalledTemp <<" times"<<std::endl;
    std::cout<<"Total no. of Student Objects destructed : "<<Student::destiCalledTemp<<std::endl<<std::endl;
}
Output :
Total no. of Student objects created : 2000
Constructor was called  1000 times
Copy Constructor was called  1000 times
Total no. of Student Objects destructed : 1000
  • The villain in this case is the getStudentObjects function from Branch class.
  • Inside the loop we created and by the help of constructor called the 1000 objects. After creating object we insert that new object inside vector, so copy constructor called 1000 times and destructor of the old 1000 Student object is called.
  • In the last line, the content was copied to vectStudents, and again 1000 copy constructor and destructor of old 1000 Student object is called. So total 2000 objects are wasted.
  • With a small change i.e. std::vector<Student> vectStudents = Branch::getStudentObjects (temp); , we still are reducing the wastage to 1000 objects. We can even more reduce the wastage by implementing two ways-
  1. Rather than returning whole vector from branch function, we have to pass the new vector as reference to the branch function. OR
  2. We can use vector’s assign function to create 1000 copies of 1 object.

Example program 2 :

#include <iostream>
#include <vector>
class Student {
public:
    static int contructorCalledTemp;
    static int destiCalledTemp;
    static int copyconstructorCalledTemp;
    Student()     {
        contructorCalledTemp++;
    }
    ~Student()    {
        destiCalledTemp++;
    }
    Student(const Student& obj) {
        copyconstructorCalledTemp++;
    }
};
int Student::contructorCalledTemp = 0;
int Student::copyconstructorCalledTemp = 0;
int Student::destiCalledTemp = 0;

class Branch
{
public:
    static std::vector<Student> getStudentObjects(int temp)
    {
        std::vector<Student> vectStudents;
        vectStudents.reserve(temp);
        for (int i = 0; i < temp; ++i) {
            vectStudents.push_back(Student());
        }
        return vectStudents;
    }
};

class BranchImproved
{
public:
        static std::vector<Student> getStudentObjects_2( int temp)
    {
        std::vector<Student> vectStudents;
        vectStudents.assign(temp, Student());
        return vectStudents;
    }
};    

int main()
{
    int temp=1000;
    Student::contructorCalledTemp = 0;
    Student::copyconstructorCalledTemp = 0;
    Student::destiCalledTemp = 0;
    std::vector<Student> vectStudents_3 = BranchImproved::getStudentObjects_2(temp);
    std::cout<<"Total no. of Student objects created : "<<(Student::contructorCalledTemp + Student::contructorCalledTemp)<<std::endl;
    std::cout<<"Constructor was called  "<<Student::contructorCalledTemp <<" times"<<std::endl;
    std::cout<<"Copy Constructor was called  "<<Student::copyconstructorCalledTemp <<" times"<<std::endl;
    std::cout<<"Total no. of Student Objects destructed : "<<Student::destiCalledTemp<<std::endl<<std::endl;
}
Output :
Total no. of Student objects created : 2
Constructor was called  1 times
Copy Constructor was called  1000 times
Total no. of Student Objects destructed : 1