Consider the following code:
template <class T>
struct myclass
{
// Select only one constructor in the following
myclass() = default; // 0
myclass() {}; // 1
myclass(): i{}, ptr{}, var{}, arr{}, vec{}, str{} {} // 2
myclass(): i(), ptr(), var(), arr(), vec(), str() {} // 3
// Data members
int i;
T* ptr;
T var;
std::array<int, 3> arr;
std::vector<T> vec;
std::string str;
};
And its use:
myclass<std::array<double, 3>> a;
myclass<std::array<double, 3>> b{};
myclass<std::array<double, 3>> c();
auto d = myclass<std::array<double, 3>>{};
auto e = myclass<std::array<double, 3>>();
So in total, mixing constructors/method of construction chosen, we have 4 * 5 = 20 cases: a0, a1, a2, a3, b0, b1, b2, b3, ..., e3
. My question is :
What cases lead to initialized members (i
is set to zero, ptr
is set to nullptr
, arr
is filled with zeros) and what cases lead to uninitialized members?
First, c
is a declaration of function (vexing parse)
For 2, 3, value-initialization of built-in will do a zero-initialization
2, 3 will call default constructor of std::string
, std::vector
(so empty)
2 will value initialize std::array
(its element are value initialized)
3 will aggregate-initialize std::array
which is an aggregate (value-initialization of its element, so 0
for int
,double
).
For 0, 1, default initialization of built-in won't initialize them
0, 1 will call default constructor of std::string
, std::vector
(so empty)
default initialization of std::array
will default initialize its elements (int
and double
uninitialized)
For myClass
, for 1, 2, 3:
For myClass
, for 0:
default-initialization performs default initialization of its member.
value-initialization performs zero initialization and then default initialization.
So members will be initialized for 2, 3, b-0, d-0, e-0