Saturday, June 28, 2008

C++: Avoid using assignments in constructors

In my post Coding better C++, I've suggested a list of techniques to improve C++ coding. I shall try to explain them one at a time in the future posts. In this post, I've talked about "4. Avoid using assignments in constructors, use initializer list to initialize members".

The initialize list is used to avoid double construction of a contained object. Take the following example:
  1 
2
Class Student
3
{
4
public:
5
Student ( const char *_name)
6
{
7
name = _name;
8
}
9
private:
10
string name;
11
};
We create an object of the Student, for example, in the following way.
 Student s (Abc);
The following executions take place:

1. string name is initialized
a. string::string() function is called
2. body of the Student::Student(const char *) constructor is called
3. the line name = _name is executed
a. string::operator=(const char *) function is called

A note to experts: we’ve ignored memory allocation steps and detailed assembly steps of the function calls to keep things simple.

As you can see the result of the step 1.a, string::string(), is discarded by step 3.a, string::operator=(const char *), the step 1.a is therefore redundant.

We can optimize this with the initializer list, in the following way:
  1 Class Student
2
{
3
public:
4
Student ( const char *_name) : name (_name)
5
{
6
}
7
private:
8
string name;
9
};
10
In this way, the string 'name' is initialized only once and with the value of _name and it calls the string::string(const char *) function directly.

Many optimizations require some kind of a trade-off. You often trade speed for clarity, simplicity, re-usability, or some other metric. But in this example, optimization requires no sacrifice at all. This constructor will generate the exact same Student object with the exception of improved performance.

3 comments:

Z said...

ahh! you just answered my question. Thank you very much. I thought, maybe you can also augment one more paragraph with this entry about initialization order; like member variables initialized using intialization-list go in the order in which they are declared - not depending on the list. I am asking you to augment this because its not very obvious to someone new to C++

luc said...

I think, in some cases the code becomes ugly through this type of member initialization.

If number of member variables in a class is quite a significant amount, then i guess the code becomes more readable when the initialization is doen through assignment inside the constructer.

Otherwise, the initialization technique mentioned here is definitely preferable.

Kaisar said...

@luc:

To me, the initializer list looks more beautiful than assignments in constructor. Well, may be, perception of the beauty of the code varies programmer to programmer. However, I wouldn't sacrifice a lot of performance because for this. Think a about a class that is being used rapidly in many places. If I can save one redundant assignment, I might be able to save a lot of CPU cycles. I would have optimized it as much as possible.


However, even if I sacrifice performance because of the beauty of the code, I would have documented it very well in my code so that no other programmer can claim I didn't consider the optimization. :)

Thanks!