Initialization in constructors, best practice?

I have been programming in C ++ for a while, and I used both methods:

class Stuff { public: Stuff( int nr ) : n( nr ) { } private: int n; } 

or

 class Stuff { public: Stuff( int nr ) { n = nr; } private: int n; } 

Note. This is not the same as this , similar, but not the same.

What is considered best practice?

+6
c ++
source share
7 answers

Initializer lists are preferred. See FAQ 10.6

+21
source share

One big advantage of using initializers: if an exception is thrown anywhere in the list of initializers, destructors will be called for those elements that have already been initialized, and only for these members.

When you use the constructor body to initialize an object, you need to handle exceptions correctly and unwind the object accordingly. It is usually much harder to qualify.

+12
source share

Use a list of initializers when possible. For int, this doesn't matter much anyway, but for a more complex member object, you get the default constructor of the called object, followed by assignment to that object, which is likely to end up being slower.

Also, you should still do this for constant members or members that don't have a default constructor.

+5
source share

If possible, use the first version.

The first is initialized using intializer lists and actually calls member constructors.

The second is the appointment. If n has a type with a default constructor, it would have already been called, and then you assigned it. If n does not have a default constructor, you will have to use the first type. Similarly, if n was a reference: int &n .

If there are no constructors from your members who directly take one of the parameters into your constructor, it may be useful to add private static functions that can perform the conversion for you.

+2
source share

I usually try to make a list of initializers when I can. Firstly, it makes it explicit that you initialize the code in the constructor. const memebers must be initialized this way.

If you just put the code in the constructor’s body, it’s quite possible that someone might decide to come and move most of it to the non-design “setting” later.

However, this can be taken overboard. I have a colleague who likes to create classes with 2 pages of initiator code, no constructor code, and possibly 2 pages for the rest of the class code. I find it hard to read.

+1
source share

The second option is not initialization, but purpose. With types that have custom default constructors, the second option calls the default constructor, and then calls the assignment operator (regardless of whether the user specified it or not) to assign the value.

Some types cannot be initialized by default: if you have an attribute without a default constructor, hold links (constant or not) or have constant attributes, they must be initialized in the list of initializers.

Arrays can be initialized with a value in the initialization list, but not in the constructor body:

 class X { public: X() : array() {} // value-initializes the array // equivalent to: // X() { for ( int i = 0; i < 10; ++i ) array[i]=0; } private: int array[10]; }; 

For POD types, you can initialize their initialization in the initialization list, but not inside the brackets:

 class X { public: X() : pod() {} // value-initializes // equivalent to (but easier to read and subtly faster as it avoids the copy): // X() { pod = {}; } private: PODType pod; }; 

Finally, some classes offer functionality using constructors that will be more complex (if achievable) after building by default.

 class X { public: X() : v(10) {} // construct a vector of 10 default initialized integers // equivalent to: // X() { for ( int i = 0; i < 10; ++i ) v.push_back(0); } private: std::vector<int> v; }; 

Finally, when they are actually equivalent, initialization lists are more idiomatic in C ++.

0
source share

I want to add that you do not need to declare a list of initializers in the header (.h). This can be done by implementing the constructor (which is very common).

So then:

 //Stuff.h class Stuff { public: Stuff( int nr ); private: int n; } //Stuff.cpp Stuff::Stuff(int nr) : n(nr) { //initalize complex members } 

is legal, and it concentrates field initialization where it matters. Sometimes we need to initialize complex elements in the body, so you have a list of initializers and complex initialization in the .cpp file.

0
source share

All Articles