There are a couple of differing styles when initializing automatically managed simple variables other than via assignment. I was wondering if there are any specific reasons to favour one over the other or is it just a matter of style.
Using parentheses is appealing because it feels similar to instantiating an object
double answer(42.0);
ComplexNumber i(0,1);
while using braces is appealing because it feels similar to initialising a container
double answer{42};
std::vector<double> i{0,1};
double i2[] = {0,1};
Is there any particular reason to favour one style over the other?
Look here: GotW #1 : Variable Initialization. It's a detailed description of answer from H. Sutter.
H. Sutter talks above in a general sense of old and new styles of Variable Initialization.
Below is showed a quick synopsis from the article, according to your start-topic context.
This pair
double answer(42.0); // (1)
double answer{42}; // (2)
in fact, is similar to the next initialization example:
widget w(x); // (d)
widget w{x}; // (e)
These are both direct initialization. However, note that the syntax {x}
creates an initializer_list
. If widget
has a constructor that takes an initializer_list
, that constructor is preferred; otherwise, if widget
has a constructor that takes whatever type x
is (possibly with conversions), that constructor is used.
There are two major differences that make (2, e) superior to (1, d):
x
is a type name, then (1, d) is a function declaration even if there is also a variable named x
in scope (see above), whereas (2, e) is never a function declaration.Second, syntax (2, e) is safer because it does not allow narrowing (a.k.a. “lossy”) conversions that are otherwise allowed for some built-in types. Consider:
int i1( 12.345 ); // ok: toss .345, we didn't like it anyway
int i2{ 12.345 }; // error: would be lossy implicit narrowing
Next pair
ComplexNumber i(0,1); // (3)
std::vector<double> i{0,1}; // (4)
is tied with initialization of complex objects. Both looks quite the same, but the second one helps us to avoid "vexing parse", like:
ComplexNumber w( real(), img() ); // oops, vexing parse
Besides of that, this way make code more clear (if we use initializer_list
, it's more clear that's initialization),
and, moreover, alleviate syntax in some cases, for instance:
draw_rect({ origin, selection }); // C++11
Sutter guildeline is: prefer to use initialization with { }
, such as vector<int> v = { 1, 2, 3, 4 };
or auto v = vector<int>{ 1, 2, 3, 4 };
, because it’s more consistent, more correct, and avoids having to know about old-style pitfalls at all. In single-argument cases where you prefer to see only the =
sign, such as int i = 42
; and auto x = anything
; omitting the braces is fine.
We can use ()-initialization for the explicit call of the special constructor.
Adding to Boris's answer there's another pitfall to avoid that's not mentioned in Herb's blog post.
The following code is illegal:
#include <initializer_list>
int main() {
auto i{42}; // not the same as 'auto i(42);'
++i;
}
The error message raised by gcc 4.7.2 is:
error: no match for 'operator++' in '++i'
The reason is that auto
deduces the type of {42}
to be std::inilializer_list<int>
rather than int
as many could believe. There's no operator ++
for std::initializer_list<int>
and hence the error. If you replace {42}
with (42)
then the code compiles fine.
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