This first problem highlights the importance of understanding what you write. Here we have a few simple lines of code—most of which mean something different from all the others, even though the syntax varies only slightly.
Problem
JG Question
1. What is the difference, if any, among the following?
widget w; // (a)
widget w(); // (b)
widget w{}; // (c)
widget w(x); // (d)
widget w{x}; // (e)
widget w = x; // (f)
widget w = {x}; // (g)
auto w = x; // (h)
auto w = widget{x}; // (i)
Guru Questions
2. What do each of the following lines do?
vector<int> v1( 10, 20 ); // (a)
vector<int> v2{ 10, 20 }; // (b)
3. Besides the cases above, what other benefits are there to using { } to initialize objects?
4. When should you use ( ) vs. { } syntax to initialize objects? Why?
Solution
This puzzle demonstrates several things:
- The difference between default initialization, direct initialization, copy initialization, and list initialization.
- The difference between using ( ) and using { } for initialization.
- A red herring that isn’t initialization at all, and which modern C++ entirely avoids.
But, most important of all: If you stick to two simple Guidelines, which we’ll cover in #4, you can ignore most of these cases and the rules are pretty simple and deliver efficient performance by default.
1. What is the difference, if any, among the following?
Let’s consider the cases one by one.
(a) is default initialization.
widget w; // (a)
This code declares a variable named w, of type widget. For most types, it is initialized using the default constructor widget::widget().
Note that w is not initialized and contains garbage values if widget happens to be a built-in type like int, or a simple “int-like” class type with what’s called a “trivial” default constructor—a type that relies on the compiler-generated default constructor, has no virtual functions or virtual base classes or data member initializers, and all its bases and members satisfy the same restrictions.
(b) is a “vexing” red herring, now mostly a historical curiosity.
widget w(); // (b)
This is a pre-modern C++ pitfall: At first glance, it may look like just another variable declaration calling a default constructor widget::widget(); in reality, thanks to a grammar ambiguity, it’s a function declaration for a function named w that takes no parameters and returns a widget object by value. (If you can’t see this at first, consider that the above code is no different from writing something like int f(); which is clearly a function declaration.)
Lest you think “aw, but those ( ) parentheses are redundant, it’s the programmer’s own fault for not just writing widget w; there!”, note that the same problem arises in those occasional cases where you think you’re initializing a variable with temporary objects:
// same problem (gadget and doodad are types)
//
widget w( gadget(), doodad() ); // pitfall: not a variable declaration
Scott Meyers long ago named this “C++’s most vexing parse,” because the standard resolves the parsing ambiguity by saying: “if it can be a function declaration, it is.”
The good news is that this is now mostly a historical curiosity, not something you should encounter in new code, because C++11 removed this pitfall. Note that C++11 does not change the meaning of the code—C++11 has great backward compatibility with C++98, including that this ambiguity still has the same meaning it always had. Rather, C++11 solves this by providing a syntax that supersedes case (b) in nearly all cases, so that we don’t need to ever fall into this pit anymore:
(c) is non-vexing and clear.
widget w{}; // (c)
Here we have the first reason to prefer { } to ( ): For any class type widget, line (c) does the “best parts” of (a) and (b)—it always initializes the variable, and is never ambiguous with a function declaration. No vex, no fuss, no muss.
“Aha, but wait, it’s not that simple!” someone might object. “What if widget has a constructor that takes a std::initializer_list? Those are greedy (preferred), so if widget has one of those wouldn’t this call that?”
The answer is no, this really is just as simple as it looks, because the standard is explicit that an empty { } list means to call the default constructor if available. However, it’s good to be aware of initializer_lists, so let’s talk about those next.
(d) and (e) are direct initialization.
Now let’s consider cases where we actually initialize w from some existing variable:
widget w(x); // (d)
widget w{x}; // (e)
Assuming x is not the name of a type, these are both direct initialization. That’s because the variable w is initialized “directly” from the value of x by calling widget::widget(x). If x is also of type widget, this invokes the copy constructor. Otherwise, it invokes a converting constructor.
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 (e) superior to (d): First, like (c), syntax (e) is unambiguous and avoids the vexing parse. If x is a type name, then (d) is a function declaration even if there is also a variable named x in scope (see above), whereas (e) is never a function declaration.
Second, syntax (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
(f) and (g) are copy initialization and copy list initialization.
This brings us to our final two non-auto cases:
widget w = x; // (f)
This is called “copy initialization.” Conceptually, the variable w is initialized using widget‘s move or copy constructor, possibly after calling another function to convert the argument implicitly (explicit conversions won’t be invoked here).
Common Mistake: This is always initialization; it is never assignment, and so it never calls T::operator=(). Yes, I know there’s an “=” character in there, but don’t let that throw you — that’s just a syntax holdover from C, not an assignment operation.
Here are the semantics:
- If x is of type widget, line (f) means the same as (d) widget w(x); except that explicit constructors cannot be used. It’s guaranteed that only a single constructor is called.
- If x is of some other type, conceptually the compiler first implicitly converts x to a temporary widget object, then move-constructs w from that temporary rvalue, using copy construction as “the slow way to move” as a backup if no better move constructor is available. Assuming that an implicit conversion is available, (f) means the same as widget w( widget(x) );.
Note that I said “conceptually” a few times above. That’s because practically compilers are allowed to, and routinely do, optimize away the temporary and, if an implicit conversion is available, convert (f) to (d), thus optimizing away the extra move operation. However, even when the compiler does this, the widget copy constructor must still be accessible, even if is not called—the copy constructor’s side effects may or may not happen, that’s all.
Now note the related syntax that adds “=“:
widget w = {x}; // (g)
This is called “copy list initialization.” It means the same as widget w{x}; except that explicit constructors cannot be used. It’s guaranteed that only a single constructor is called.
(h) and (i) are also copy initialization, but simpler.
auto w = x; // (h)
auto w = widget{x}; // (i)
The semantics are just like (f) and (g), except simpler to teach, learn, and use because using auto guarantees the right-hand expression’s type will be deduced exactly. Note that the (i) syntax works fine for both implicit and explicit conversions.
Line (h) means the same as (d), type_of_x w(x);. Only a single copy constructor is called. This is guaranteed to stay true as the program evolves: Because line (h) does not commit to an explicit type, it is guaranteed to be both maximally efficient because there can be no conversion involved, and maximally robust under maintenance as the type of w “auto”-matically tracks the type of x which may change as the program is maintained.
Line (i) is the most consistent spelling when you do want to commit to a specific type and explicitly request a conversion if needed, and once again the { } syntax happily avoids lossy narrowing conversions. In practice on most compilers, only a single constructor is called—similarly to what we saw with (f) and (g), conceptually there are two constructor calls, a converting or copy constructor to create a temporary widget{x} followed by a move to move it to w, but compilers routinely elide the latter.
In general, I recommend that you try out these two forms, and increasingly prefer using them as you grow comfortable with them. I’m at the point where I’m now inclined to write virtually all of my local variable declarations this way. (I know some of you will be skeptical about this broad claim—more on “the auto question” in another GotW.)
2. What do each of the following lines do?
In the Question 2 code, we’re creating a vector<int> and passing the arguments 10 and 20 to its constructor—in the first case as ( 10, 20 ) and in the second case as { 10, 20 }.
Both will call a constructor, but which one(s)? Well, vector<int> has several constructors that can take two parameters, but only two could be correctly called with the parameters 10 and 20. Ignoring defaulted optional allocator parameters for simplicity, the two constructors are:
vector( size_t n, const int& value ); // A: n copies of value
vector( initializer_list<int> values ); // B: copy of values
There are two simple C++ rules that tell us which one will be called for the code in question:
- The syntax { /*…*/ } used in an expression context gives you an initializer_list.
- Constructors that take an initializer_list are preferred over other constructors, and so can hide other constructors that might otherwise be viable.
Armed with those two tidbits, the answer is simple:
vector<int> v1( 10, 20 ); // (a) calls A: 10 copies of the value 20
assert( v1.size() == 10 );
vector<int> v2{ 10, 20 }; // (b) calls B: the values 10 and 20
assert( v2.size() == 2 );
3. Besides the cases above, what other benefits are there to using { } to initialize objects?
For one thing, it’s called “uniform initialization” because it’s, well, uniform—the same for all types, including aggregate structs and arrays and std:: containers, and without the “vexing parse” annoyance:
struct mystruct { int x, y; };
// C++98
rectangle w( origin(), extents() ); // oops, vexing parse
complex<double> c( 2.71828, 3.14159 );
mystruct m = { 1, 2 };
int a[] = { 1, 2, 3, 4 };
vector<int> v; // urk, need more code
for( int i = 1; i <= 4; ++i ) v.push_back(i); // to initialize this
// C++11 (note: "=" is mostly optional)
rectangle w = { origin(), extents() };
complex<double> c = { 2.71828, 3.14159 };
mystruct m = { 1, 2 };
int a[] = { 1, 2, 3, 4 };
vector<int> v = { 1, 2, 3, 4 };
And note that this isn’t just an aesthetic issue. Consider writing generic code that should be able to initialize any type… and while we’re at it, let’s gratuitously use perfect forwarding as an example:
template<typename T, typename ...Args>
void forwarder( Args&&... args ) {
// ...
T local = { std::forward<Args>(args)... };
// ...
}
forwarder<int> ( 42 ); // ok
forwarder<rectangle> ( origin(), extents() ); // ok
forwarder<complex<double>>( 2.71828, 3.14159 ); // ok
forwarder<mystruct> ( 1, 2 ); // ok because of {}
forwarder<int[]> ( 1, 2, 3, 4 ); // ok because of {}
forwarder<vector<int>> ( 1, 2, 3, 4 ); // ok because of {}
The last three lines would not be legal if forwarder used ( ) initialization syntax internally.
The new { } syntax works pretty much everywhere, including to initialize members:
widget::widget( /*...*/ ) : mem1{init1}, mem2{init2, init3} { /*...*/ }
And, as icing on the take, it’s often just plain convenient to pass function arguments, or return a value, without a type-named temporary:
void draw_rect( rectangle );
draw_rect( rectangle(origin, selection) ); // C++98
draw_rect({ origin, selection }); // C++11
rectangle compute_rect() {
// ...
if(cpp98) return rectangle(origin, selection); // C++98
else return {origin, selection}; // C++11
}
4. When should you use ( ) vs. { } syntax to initialize objects? Why?
Here’s the simple guideline:
Guideline: 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. …
That covers the vast majority of cases. There is only one main exception:
… In rare cases, such as vector<int> v(10,20); or auto v = vector<int>(10,20);, use initialization with ( ) to explicitly call a constructor that is otherwise hidden by an initializer_list constructor.
However, the reason this should be generally “rare” is because default and copy construction are already special and work fine with { }, and good class design now mostly avoids the resort-to-( ) case for user-defined constructors because of this final design guideline:
Guideline: When you design a class, avoid providing a constructor that ambiguously overloads with an initializer_list constructor, so that users won’t need to use ( ) to reach such a hidden constructor.
Acknowledgments
Thanks in particular to the following for their feedback to improve this article: Michal Mocny, Jay Miller, “Alexey,” “praetorian20,” Francisco Lopes, “Neil,” Daryle Walker.
Most of the talks I gave at 

