My short summary for non static data members initialization from modern C++. A very useful feature. Should we use it or not?
Introduction
Non-static data member initializers | Paper N2756 |
Visual Studio | Since VS 2013 |
GCC | Since GCC 4.7 |
Intel Compiler | Since version 14.0 |
Clang | Since Clang 3.0 |
Previously, you could only initialize static, integral and const members of a class. Now, it is extended to support non static members that do not need to be const and may have any type.
Basic Example
class SimpleType
{
private:
int a { 1 }; int b { 1 }; string name { "string" };
public:
SimpleType() {
cout << "SimpleType::ctor, {"
<< a << ", "
<< b << ", \""
<< name << "\"}"
<< endl;
}
~SimpleType() {
cout << "SimpleType::destructor" << endl;
}
};
If we create an object of type SimpleType
:
SimpleType obj;
On the output, we will get:
SimpleType::ctor, {1, 1, "string"}
All of the member variables were properly initialized before our constructor was called. Note that we did not initialize members in the constructor. Such approach is not only available for simple types like int
, but also for a complicated type like std::string
.
Why Useful
- Easier to write
- You are sure that each member is properly initialized.
- You cannot forget to initialize a member like when having a complicated constructor. Initialization and declaration are in one place - not separated.
- Especially useful when we have several constructors.
- Previously, we would have to duplicate initialization code for members or write custom method like
InitMembers()
that would be called in constructors. - Now, you can do a default initialization and constructors will only do its specific jobs…
More Details
Let’s now make some more advanced example:
SimpleType
with a new constructor:
class SimpleType
{
private:
int a { 1 }; int b { 1 }; string name { "string" };
public:
SimpleType() { }
SimpleType(int aa, int bb)
: a(aa), b(bb) {
std::cout << "SimpleType::ctor(aa, bb), {"
<< a << ", "
<< b << ", \""
<< name << "\"}"
<< std::endl;
}
~SimpleType() {
cout << "SimpleType::destructor" << endl;
}
};
And AdvancedType
:
class AdvancedType
{
private:
SimpleType simple;
public:
AdvancedType() {
cout << "AdvancedType::ctor" << endl;
}
AdvancedType(int a) : simple(a, a) {
cout << "AdvancedType::ctor(a)" << endl;
}
~AdvancedType() {
cout << "AdvancedType::destructor" << endl;
}
};
So now, AdvancedType
uses SimpleType
as a member. And we have two constructors here.
If we write:
AdvancedType adv;
We will get:
SimpleType::ctor, {1, 1, "string"}
AdvancedType::ctor
SimpleType::ctor
(default) was called before AdvancedType::ctor
. Note that AdvancedType::ctor
does nothing beside printing…
Then, if we write:
AdvancedType advObj2(10);
We will get:
SimpleType::ctor(aa, bb), {10, 10, "string"}
AdvancedType::ctor(a)
So this time, the second constructor of SimpleType
was called.
Note: Even if you have a default initialization for a member, you can easily overwrite it in a constructor. Only one initialization is performed.
Any Negative Sides?
The feature that we discuss, although it looks nice and easy, has some drawbacks as well.
- Performance: When you have performance critical data structures (for example, a
Vector3D
class), you may want to have "empty" initialization code. You risk is having uninitialized data members, but you will save several instructions. - Making class non-aggregate: I was not aware of this issue, but Shafik Yaghmour noted that in the comments below the article.
- In C++11, the spec did not allow aggregate types to have such initialization, but in C++14 this requirement was removed.
- Link to the StackOverflow question with details
Should You Use It?
I do not think there are any serious drawbacks of using non static data members initialization. You should be aware of the negative sides (mentioned in the section above), but for something like 90% of cases it should be safe to use.
If your coding guideline contains a rule about initialization of every local variable in the code, then, in my opinion, non static data member initialization completes this approach.
BTW: If that puts any standard, this concept is not forbidden in Google C++ guide
Your Turn
You can play with my basic code here: nonstatic_members_init.cpp
What do you think about non static data member initialization?
Do you use it in your code?
You can vote in my simple survey at my blog.
Links