Is there any subtle difference between these two ways of initializing variables in C++11?
vector<double> v { 0.0, 1.1, 2.2, 3.3 };
vector<double> v = { 0.0, 1.1, 2.2, 3.3 };
Can the latter be used for all the same cases as the first one?
Stroustrup claims in TCPL4ED that the first way is the only one that can be used in every context, and thus recommends it. Later on, he seems to imply that the second one is just a different way of writing the first one.
In the initializer list, the order of execution takes place according to the order of declaration of member variables. While using the initializer list for a class in C++, the order of declaration of member variables affects the output of the program.
The most common benefit of doing this is improved performance. If the expression whatever is the same type as member variable x_, the result of the whatever expression is constructed directly inside x_ — the compiler does not make a separate copy of the object.
Conclusion: All other things being equal, your code will run faster if you use initialization lists rather than assignment.
Initialization lists allow you to choose which constructor is called and what arguments that constructor receives. If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.
vector<double> v { 0.0, 1.1, 2.2, 3.3 };
Is a direct-list-initialization. It means that it is initialized with a constructor taking an initializer list.
Constructor :
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
vector<double> v = { 0.0, 1.1, 2.2, 3.3 };
Is a copy-list-initialization.
The standard is pretty clear :
8.5.4 List-initialization [dcl.init.list]
List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, and the comma-separated initializer-clauses of the list are called the elements of the initializer list. An initializer list may be empty. List-initialization can occur in direct-initialization or copyinitialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization. [ Note: List-initialization can be used :
- as the initializer in a variable definition
[...]
Example :
std::complex<double> z{1,2}; [...] std::map<std::string,int> anim = { {"bear",4}, {"cassowary",2}, {"tiger",7} };
For the difference between both, we should go a little bit further :
13.3.1.7 Initialization by list-initialization [over.match.list]
- For direct-list-initialization, the candidate functions are all the constructors of the class T.
- For copy-list-initialization, the candidate functions are all the constructors of T. However, if an
explicit
constructor is chosen, the initialization is ill-formed. [ Note: This restriction only applies if this initialization is part of the final result of overload resolution — end note ]
The purpose of uniform initialization was (in part) to remove the difference between these two constructs. To ensure that they would have the same functionality.
Sadly, they failed. There is exactly one difference between direct-list-initialization (ie: T t{...}
) and copy-list-initialization (ie: T t = {...}
). You don't need a copy/move constructor for copy-list-initialization (despite the name); section 8.5.4 doesn't list that as a requirement. There's no notion of a temporary being constructed that might be elided away. They have identical behavior except:
Copy-list-initialization will fail if it selects an explicit
constructor. That's the only difference.
It's hard to give a quote from the spec, because there are only 3 mentions of what copy-list-initialization is. One is in 8.5.4, where it defines that copy-list-initialization is a form of list-initialization, another stating that returning a braced-init-list uses copy-list-initialization. And the last in 13.3.1.7, where it states the above exception:
In copy-list-initialization, if an
explicit
constructor is chosen, the initialization is ill-formed.
So that's the only difference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With