C++ Constructors vs Initialization Lists speed comparison

20,498

Solution 1

The difference is for types with no trivial default constructor, which is called for you by compiler in your class B. Your class B is equivalent to:

 class B {
   private:
     SleepyInt a, b;

   public:
     // takes at least 20s
     B(int a_var, int b_var) : a(), b()
     //                      ^^^^^^^^^^ 
     {
        a = a_var;
        b = b_var;
     }
  };

If you do not place member variable or base class constructor in initialization list - ithe default constructor is called for them. int is basic type - its default constructor costs nothing - so no difference in your example, but for more complex types constructor+assignment might cost more than just constructing.

Some funny example, just to illustrate the difference:

class SleepyInt {
public:
  SleepyInt () { 
    std::this_thread::sleep_for(std::chrono::milliseconds( 10000 ));  
  }
  SleepyInt (int i) {}
  SleepyInt & operator = (int i) { return *this; }
};

class A {
   private:
     SleepyInt a, b;

   public:
     A(int a_var, int b_var):a(a_var), b(b_var) {}; 
 };

 class B {
   private:
     SleepyInt a, b;

   public:
     // takes at least 20s
     B(int a_var, int b_var) {
        a = a_var;
        b = b_var;
     }
};

Solution 2

It is commonly accepted practice to use initialization lists as opposed to assignment in a constructor, and there's a very good reason for that.

Initialization lists can be used to initialize both POD (Plain Old Data) and user-defined types. When initializing a POD type, the effect is exactly the same as an assignment operator, meaning there is no performance difference between initialization lists or assignment in a constructor for POD types.

When we consider non-POD types things get more interesting. Before the constructor is called, constructors for the parent class and then any contained members are invoked, and by default the no-argument constructor is called. Using an initialization list you are able to choose which constructor is called.

So to answer the question, there is a performance difference, but only when initializing non-POD types.

Solution 3

If members are of more or less complex types, then the assignment initialization will first cause the default constructor call and then operator=, which may take longer.

Solution 4

There won't be a performance improvement if the types are built-in/intrinsic type.

That said:

Conclusion: All other things being equal, your code will run faster if you use initialization lists rather than assignment.

Solution 5

Initialization list is benefical reference types, member class objects, or const members. Otherwise it takes more time.

Look at my test code:

#include <iostream>
#include <ctime>

using namespace std;

class A{
    int a;
public:
    A(int a_):a(a_){}
};

class B{
    int b;
public:
    B(){
    }

    B(int b_){
        b=b_;
    }
};

class C{
    B b;
public:
    C(int c_):b(c_){
    }
};

class D{
    B b;
public:
    D(int d_){
        b=d_;
    }
};

int main()
{
    clock_t start1[10], start2[10], end1[10], end2[10];
    for(int j=0;j<10;j++){
        start1[j]=clock();
        for(int i=0;i<100000;i++){   
            A *newA=new A(i);
            delete newA;
        }
        end1[j]=clock();
        start2[j]=clock();
        for(int i=0;i<100000;i++){   
            B *newB=new B(i);
            delete newB;
        }
        end2[j]=clock();
    }
    double avg1=0, avg2=0;
    for(int i=0;i<10;i++){
        avg1+=(end1[i]-start1[i]);
        avg2+=(end2[i]-start2[i]);
    }
    cout << avg1/avg2 << endl;

    for(int j=0;j<10;j++){
        start1[j]=clock();
        for(int i=0;i<100000;i++){   
            C *newC=new C(i);
            delete newC;
        }
        end1[j]=clock();
        start2[j]=clock();
        for(int i=0;i<100000;i++){   
            D *newD=new D(i);
            delete newD;
        }
        end2[j]=clock();
    }
    avg1=avg2=0;
    for(int i=0;i<10;i++){
        avg1+=(end1[i]-start1[i]);
        avg2+=(end2[i]-start2[i]);
    }
    cout << avg1/avg2 << endl;

    system("pause");
    return 0;
}



Example outputs like this:

1.02391
0.934741

Share:
20,498
Sebi
Author by

Sebi

Updated on July 09, 2022

Comments

  • Sebi
    Sebi almost 2 years

    Are there any differences in execution time between constructors and initialization lists?(or is it just a matter of coding preference). I have a set of objects that needs to be created frequently and would like to know if there is any performance gain by using initialization lists instead of constructors.

    If I were to create a million instances of class A and another million of class B which choice would be better(the objects represent packets generated within a network hence these numbers).

     class A {
       private:
         int a, b;
    
       public:
         A(int a_var, int b_var):a(a_var), b(b_var) {}; 
     };
    
     class B {
       private:
         int a, b;
    
       public:
         B(int a_var, int b_var) {
            a = a_var;
            b = b_var;
         }
    };
    

    If any of the constructors is faster than the other for primitive types(as in the example) will it be faster if a and b were to be replaced by types?

    Type example:

     class AType {
       private:
         string a, b;
    
       public:
         AType(string a_var, string b_var):a(a_var), b(b_var) {}; 
    };
    
  • chris
    chris over 11 years
    It won't, actually, as a and b are ints.
  • Yexo
    Yexo over 11 years
    Only true for non-POD types. If the members are simple ints like in the example there is no difference.
  • Sebi
    Sebi over 11 years
    How will types affect the execution speed?
  • Michael Krelin - hacker
    Michael Krelin - hacker over 11 years
    I'm not sure what you mean by "replaced by types". I interpreted it as replaced by more complex types.
  • Sebi
    Sebi over 11 years
    If a and b were to be replaced by objects
  • Michael Krelin - hacker
    Michael Krelin - hacker over 11 years
    That's exactly what I mean. If there are constructors involved, then first default constructors are called and then assignment is performed.
  • Michael Krelin - hacker
    Michael Krelin - hacker over 11 years
    And, @Yexo, that's also regarding your comment — I was answering the "replaced by types" question.
  • Yexo
    Yexo over 11 years
    Yes, your answer "which may take longer" is technically correct, but maybe it'd be nice to expand a bit on it that it's mostly true for non-POD types.
  • Sebi
    Sebi over 11 years
    Hmm you make a sleep in the constructor and that explains the delay. But what if we make only assignments(meaning that a and b are objects and they are only assigned in class A and B
  • PiotrNycz
    PiotrNycz over 11 years
    @Sebi do you mean a and b are not members of A and B?
  • Sebi
    Sebi over 11 years
    Yes I was referring to a case where a and b are types and are already instantiated before being passed to those contructors
  • chris
    chris over 11 years
    @MichaelKrelin-hacker, I see it in there now. It's a bit hidden, as it sort of sounds like it assumes that int etc. have default constructors. It might be worth making a little more explicit.
  • PiotrNycz
    PiotrNycz over 11 years
    @Sebi I am not sure I understand. Could you update the question with new example?
  • chris
    chris over 11 years
    @Sebi, I'm not sure I understand you quite right, but there's no way apart from the type not having one to stop the compiler from calling the default constructor of your data members before the body of the constructor begins, except by using a member initializer.
  • PiotrNycz
    PiotrNycz over 11 years
    @Sebi your AType constructor might run faster than BType. Sometimes it might happen that some smart optimization will optimize the default constructor away - so they will be equivalent. Just better to use initialization list - some default constructors can't be optimized away - as my SleepyInt example.
  • Michael Krelin - hacker
    Michael Krelin - hacker over 11 years
    Okay, guys, I've added this part of the question to my answer ;-)