Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializer list vs Constructor assignment vs variable defining [duplicate]

I'm trying to understand the real difference between the following Classes.

class A
{
public:
    A()
    :width(500)
    ,height(300){};
    int width;
    int height;
};

class B
{
public:
    B()
    {
        width = 500;
        height = 300;
    };
    int width;
    int height;
};

class C
{
public:
    int width = 500;
    int height = 300;
};

Which one do you think is the best way to initialize width and height variables in a class?

Should I stick to one way over the others?

like image 512
Zack Lee Avatar asked Jul 05 '18 03:07

Zack Lee


1 Answers

This excerpt has been taken from "Inside the C++ Object Model" by Stanley B. Lippman.

You must use the member initialization list in the following cases in order for your program to compile:
1. When initializing a reference member
2. When initializing a const member
3. When invoking a base or member class constructor with a set of arguments
4. A few efficiency cases. (Here the program is correct w/o member initialization list)

For points 1-3, member initialization list is a must.
For point 4, it is not compulsory.

For example(point 4), given :

class Word {
   String _name;
   int _cnt;
   public:
   // not wrong, just naive ...
   Word() {
      _name = 0;
      _cnt = 0;
   }
};

This implementation of the Word constructor initializes _name once, then overrides the initialization with an assignment, resulting in the creation and the destruction of a temporary String object.

A significantly more efficient implementation would have been coded:

// preferred implementation
Word::Word : _name( 0 )
{
    _cnt = 0;
}

Due to this optimisation, a lot of people prefer member initialization list, as a default approach to write constructors.

// some insist on this coding style
Word::Word()
   : _cnt( 0 ), _name( 0 )
   {}

A reasonable question to ask at this point is, what actually happens to the member initialization list?

The compiler iterates over the initialization list, inserting the initializations in the proper order within the constructor prior to any explicit user code.
For example, the previous Word constructor is expanded as follows:

// Pseudo C++ Code
Word::Word( /* this pointer goes here */ )
{
   _name.String::String( 0 );
   _cnt = 0;
}

Note : The order in which the list entries are set down is determined by the declaration order of the members within the class declaration, not the order within the initialization list. In this case, _name is declared before _cnt in Word and so is placed first.

So coming back to your question :

class B is fine(since you are using primitive datatypes).

class A will generate the same code as class B

As for class C, the default constructor is first called, and then initialization of width and height would happen. This method should be preferred when there are going to be more than 1 constructor, and for each constructor width and height need to be defaulted to your desired values.

However, since the advent of C++11, and use of {} as uniform initialization, a more recommended approach for writing class C would be :

class C
{
    public:
    int width {500};
    int height {300};
};
like image 158
badola Avatar answered Oct 12 '22 13:10

badola