>

Monday, 14 December 2015

Initialization List

Initialization List:
 
       Whenever an object of a class is created, its constructor gets called. If the class is derived from a parent class ,then its parent’s default constructor gets called.
 
       Example:
 
#include <iostream>
class Foo
{
        public:
        Foo() { std::cout << "Foo's constructor" << std::endl; }
};
class Bar : public Foo
{
        public:
        Bar() { std::cout << "Bar's constructor" << std::endl; }
};
 
int main()
{
        // a lovely elephant ;)
        Bar bar;
}
 
       The object bar is constructed in two stages: first, the Foo constructor is invoked and then the Bar constructor is invoked. The output of the above program will be to indicate that Foo's constructor is called first, followed by Bar's constructor.
 
        If the parent class takes some arguments to its constructor, the initialization comes into picture. An initialization list immediately follows the constructor's signature, separated by a colon: 
 

 
Also the initialization list also lets you specify which constructor gets called for the objects that are fields of the class.

If there are multiple fields, then the names of the objects being initialized should appear in the order they are declared in the class.

 
 
Note1: Situation where initialization list must be used
Constants and references can only be initialized in the initialization list
Example:

 
Note2: Are there other cases when the initialization list is helpful?

A: Yes. For instance, if you have a constructor parameter with the same name with a field you want to assign it to, the compiler knows how to resolve correctly the names:
Code:
class foo
{
   int data;
 
public:
   foo(int data):data(data){}
};
The above is equivalent to:
Code:
class foo
{
   int data;
 
public:
   foo(int data)
   {
       this->data = data;
   }
};
 
 
Note 3: Prefer Initialization to assignment in constructors
Construction of objects proceeds in two phases:
  1. Initialization of data members.
  2.  
For the NamedPtr classes, this means that a constructor for the string object name will always be called before you ever get inside the body of a NamedPtr constructor. The only question, then, is this: which string constructor will be called?
That depends on the member initialization list in the NamedPtr classes. If you fail to specify an initialization argument for name, the default string constructor will be called. When you later perform an assignment to name inside the NamedPtr constructors, you will call operator= on name. That will total two calls to string member functions: one for the default constructor and one more for the assignment.
On the other hand, if you use a member initialization list to specify that name should be initialized with initNamename will be initialized through the copy constructor at a cost of only a single function call. 
Even in the case of the lowly string type, the cost of an unnecessary function call may be significant, and as classes become larger and more complex, so do their constructors, and so does the cost of constructing objects. If you establish the habit of using a member initialization list whenever you can, not only do you satisfy a requirement for const and reference members, you also minimize the chances of initializing data members in an inefficient manner.
In other words, initialization via a member initialization list is always legal, is never less efficient than assignment inside the body of the constructor, and is often more efficient. Furthermore, it simplifies maintenance of the class , because if a data member's type is later modified to something that requires use of a member initialization list, nothing has to change.

 

Why should member initialization list should be preferred:

Initialization lists. In fact, constructors should initialize as a rule all member objects in the initialization list. Consider the following constructor that initializes member object x_ using an initialization list:
 Fred::Fred() : x_(whatever) { }.
The most common benefit of doing this is improved performance. For example, if the expression whatever is the same type as member variable x_, the result of the whatever expression is constructed directly inside x_ — the compiler does not make a separate copy of the object. Even if the types are not the same, the compiler is usually able to do a better job with initialization lists than with assignments.
The other (inefficient) way to build constructors is via assignment, such as:
Fred::Fred() { x_ = whatever; }.
In this case the expression whatever causes a separate, temporary object to be created, and this temporary object is passed into the x_ object's assignment operator. Then that temporary object is destructed at the ;. That's inefficient.
As if that wasn't bad enough, there's another source of inefficiency when using assignment in a constructor: the member object will get fully constructed by its default constructor, and this might, for example, allocate some default amount of memory or open some default file. All this work could be for naught if the whatever expression and/or assignment operator causes the object to close that file and/or release that memory (e.g., if the default constructor didn't allocate a large enough pool of memory or if it opened the wrong file).
Conclusion: All other things being equal, your code will run faster if you use initialization lists rather than assignment.

0 comments:

Post a comment