Is that way of using constructor really better ?

Started by
28 comments, last by Servant of the Lord 11 years, 6 months ago
Hello.
Not so long ago I started to learn D3D11 and at the moment I'm swimming through "Beginning DirectX 11 Game Programming" book. I found one thing, which I'm curious about. Author said that constructor’s member initialize list can be more efficient and is better programming practice than letting a constructor do the job in default way.

My question is as in topic, is that way of initializing members really better ?

Example from book:

D3DBase::D3DBase() : driverType_( D3D_DRIVER_TYPE_NULL ), featureLevel_( D3D_FEATURE_LEVEL_11_0 ),
d3dDevice_( 0 ), d3dContext_( 0 ), swapChain_( 0 ), backBufferTarget_( 0 )


Thank you in advance for any help.
Advertisement
Yes.

Constructing your members with initial values is always as good as or better than constructing your members with default values and then assigning them an "initial" value later.

Why?

(1) it's often less work (cpu cycles, memory)
(2) it's often less code... the most efficient code is code you don't write
(3) your invariants are never ever violated (the object is never in an invalid state)
(4) some kinds of members, eg. references, must be initialized using an initializer list, so just do them all that way for consistency

There are some coding standards, such as the famous Google guidelines, that discourage you from initializing member variables using initializer lists. Such standards generally forbid the use of other features introduced into the language in the early 1990s and were obviously written either by a summer student or someone trying hard to sabotage the use of C++ in their organization to the benefit of their own religious language fervour. You should aim not to be one of those people.

Stephen M. Webb
Professional Free Software Developer

Not just references, but also inherited classes must be constructed in initializer lists:
SubClass::SubClass(int blah) : BaseClass(blah) { }

With C++11 you can use "constructor delegating" (to call one constructor from another constructor) - this must also be done by initializer lists:
class MyClass()
{
public:
MyClass() : MyClass("Unnamed", 5ft + 9in, BrownColor, 160lbs) {}
MyClass(std::string name, Color eyeColor) : MyClass(name, 5ft + 9in, eyeColor, 160 lbs) {}
MyClass(std::string name, int height, int weight) : MyClass(name, height, BrownColor, weight) {}
MyClass(std::string name, int height, Color eyeColor, int weight) : name(name), height(height), eyeColor(eyeColor), weight(weight) {}
}

[size=2]The above is C++11 specific code.

How-so ever! Also in C++11, you get 'Non-static data member initializers'. *squeals with joy*

This will allow you to do this instead:
class MyClass()
{
public:
MyClass() : {}
MyClass(std::string name, Color eyeColor) : name(name), eyeColor(eyeColor) {}
MyClass(std::string name, int height, int weight) : name(name), height(height), weight(weight) {}
MyClass(std::string name, int height, Color eyeColor, int weight) : name(name), height(height), eyeColor(eyeColor), weight(weight) {}

private:
std::string name = "Unnamed"; //I get to do default initialization right in the class body! Sweet!
int height = 5ft + 9in;
int weight = 160lbs;
Color eyeColor = BrownColor;
}
[edit: I was waaaay off on my original comment]

@Servant of the Lord: you should prefix literals with an underscore, as literal suffixes not starting with an underscore are reserved for future use. But thanks for reminding me that they exist!
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Most modern compilers will optimize the trivial stuff. So I only stick important things (large items, parent classes, references, ect...) in the initializer list, as I really don't like them. My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.

My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.


Ah, but should initialisation be in the initialiser list order, or the order you declared them in the class declaration?

FWIW many coding standards suggest keeping your initialiser lists in the same order as your member declarations for exactly this reason.
[size="1"]

[quote name='Ryan_001' timestamp='1349347882' post='4986714']
My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.


Ah, but should initialisation be in the initialiser list order, or the order you declared them in the class declaration?

FWIW many coding standards suggest keeping your initialiser lists in the same order as your member declarations for exactly this reason.
[/quote]

Their order in the class definition is either for readability/clarity, or compactness/cache coherency. No one orders their variables in intialization order, at least, no one outside of C++. Not to mention dependencies can change based on the constructor that is chosen. If the order of initialization occurs in order of the intialization list, then at least you have some control in regards to dependencies. Course IMO the best solution is just to use intializtion lists when absolutely necessary, use standard C++ code the rest of the time.

use intializtion lists when absolutely necessary, use standard C++ code the rest of the time.

The initializer lists are standard C++ code.

- Jason Astle-Adams


[quote name='Ryan_001' timestamp='1349347882' post='4986714']
My big issue is that the order items are initlialized in the initializer list is not the same order as they are listed. Which for dependent items can really lead to some hard to track down bugs.


Ah, but should initialisation be in the initialiser list order, or the order you declared them in the class declaration?

FWIW many coding standards suggest keeping your initialiser lists in the same order as your member declarations for exactly this reason.
[/quote]
That, and because the language standard clearly and unambiguously specifies that member data is initialized in the order of declaration regardless of the order in which they appear in initializer lists. If there is a compiler that does not issue a warning when you put initializers out of order, you should switch to one that does. If you ignore the warnings the compiler gives you, blame only yourself.

If your coding standards suggest you write bad code, consider dropping that standard.

Consider also that if other people have to maintain your code, and they have become used to good practices such as initializing all member data in initializer lists, then you increase the maintenance cost of your software.

Stephen M. Webb
Professional Free Software Developer

One gotcha though related to initializer lists is that exception safety is not possible if allocating memory to raw pointers.

Consider

Bar::Bar()
{
throw SomeException();
}

class Foo
{
int *somePointer;
Bar bar;
};

Foo::Foo()
:somePointer(new int[10])
{
}

Foo::~Foo()
{
delete[] somePointer;
}


The above code has a memory leak, somePointer is never freed since construction of Bar throws an exception.

This topic is closed to new replies.

Advertisement