Parenthesis "()" - call constructor
Equal assignment "=", what it calls depends on the left hand side
- Left side is a declaration, then it calls constructor/copy-constructor
class A;
A a = 1; // A has a constructor takes an integer, then it calls constructor
A b = a; // copy constructor
- Left side is a variable, then it calls assignment operator
A a = 1;
A b = 2;
b = a; // assignment operator
Brace "{}", it calls constructor
- If initialization-list constructor is defined and matches the calling, then call initialization-list constructor
- If initialization-list constructor is defined but does not matches the calling, then call normal constructor
- If initialization-list is not defined, then call normal constructor
2. Three categories initialization
Default value of class member variables
Read this for more, C++11 features - Improvement on object construction.
class Foo {
int mX = 0; // Ok
double mY{0.0}; //Ok
char mZ('z'); // Not ok
};
In the initialization of default value of class member variables, both "=" and "{}" work but "()" does not. Eve thought initialization the member variables in this way is not recommended because of the maintenance problem if this class has a few other constructors. But it is good to use for the classes that do not have a user-defined constructor. And one advantage of this technique is that developers do not need to worry about the order of member appearing in the initialization list of a constructor. Normally the order has to comply with the order of the member variables declaration, otherwise warning is generated and some subtle errors could occur if dependency exists.
Initialization when declaration
When declare variables, initialize them with default value.
void Foo()
{
int mX = 0; // Ok
double mY{0.0}; //Ok
char mZ('z'); // Ok
}
All three work fine in this case. Just be careful using "{}" together with "auto". In C++11 it has the type of "std::initializer-list<T>".
Initialization of non-copyable types
Non-copyable types:
- atomic variables in C++11
- Any user-defined types that have private/deleted copy-constructor/assignment operator. Read this for more, C++11 features - Explicitly defaulted/deleted member functions
The following example is from Scott Meyer's book - Effective Modern C++
std::atomic<int> a{0}; // Ok
std::atomic<int> b(0); // Ok
std::atomic<int> c = 0; // Not ok
This a reasonable and logical consequence as we discussed in the first section, "=" is to call either copy-constructor or assignment operator, which are exactly suppressed in non-copyable classes.
Only "{}" work for all 3 initialization scenarios. Probably why it is called uniform initialization.
3. Pitfalls of braces "{}"
Braces "{}" is the only one that works for the 3 cases described in the second section. Besides braces "{}" fixes quite a few other things in C++98, (read C++11 - Initializer-list (Part I) for more)
- Default value initialization of STL, like std::vector
- Most vexing parsing problem
But it is not perfect either. It has overloading problems with other types. If a constructor with a initializer-list as the first augment exists, then compiler will always try to match it first then the rest, even thought there seems to be better choices. As long as the promotion can take place and match the constructor with initializer-list, then it will use it rather than any other, even though there might be better choices. Another issues is that it does not work with narrowing when comes to variable initialization. Read C++11 - Initializer-list (Part II).
Watch out the class with initializer-list constructor, using "()" or "{}" to initialize variables may call two different constructors. For instance std::vector. std::vector<int> a(10, 10) and std::<int> b{10, 10} are very different.
Bibliography:
[1] Scotts Meyer, "Effective Mordern C++", O'REILLY, 2014 First Release
[2] Bjarne Stroustrup, "The C++ Programming Language", C++11, 4th Edition
[3] C++ Reading Club @ IG Group
No comments:
Post a Comment