C++ treats aggregates differently from non-aggregates. Aggregates are basically plain old C-style structs and arrays. Initialising aggregates is done with braces. In C++11, uniform initialisation is also done with braces.
Aggregate initialisation initialises each member directly. So we can initialise non-movable types like std::lock_guard
struct Agg {
std::lock_guard<std::mutex> lk;
}
std::mutex m;
Agg a = { std::lock_guard(m); } // OK
For backwards compatibility with C, aggregate initialisation will value initialise any trailing data members.
struct Foo {
int a;
int b;
int c;
}
Foo f = {1}; // b and c are value-initialized (to 0)
Zero-argument initialisation
For a type T
, T{}
can do uniform initialisation or aggregate initialisation. This will depend on whether T
is an aggregate or not.
Also T()
can do value-initialisation as a special case.
emplace_back
Emplace back with Args&&... args
constructs using a placement-new expression like ::new (p) T(std::forward<Args>(args)...)
. Note that this is using parens, not braces.
std::vector<std::array<int, 3>> vec_arr; // vector of aggregate
vec_arr.emplace_back(1, 2, 3); // error in C++17
So, the above code fails to compile as std::array<int, 3>(1, 2, 3)
fails because std::array
has no constructor taking three ints.
C++20 Parens-init for aggregate
In C++20, initialising aggregates is allowed from a parenthesised list of values.