Consider:
class x {
std::array<int, 4> data_;
public:
x() /*no reference to data_ here*/ {}
};
Do the int
elements in data_
get zeroed, or is their value indeterminate?
By extension is that also true in this case:
class x {
std::variant<std::array<int, 4> /*other stuff here*/> data_;
public:
x() /*no reference to data here*/ {
data_.emplace<std::array<int, 4>>(/* no args */);
}
};
EDIT:
Extension: Is there a way I can get the desired behaviour from the variant (to not initialise the data).
If I pair the two example together I should be able to do:
struct no_init_array {
std::array<int, 4> array;
no_init_array() { } //does nothing
};
class x {
std::variant<no_init_array/*other stuff here*/> data_;
public:
x() /*no reference to data here*/ {
//call default ctor of no_init_array
//which does not init the std::array (I hope)
data_.emplace<no_init_array>(/* no args */);
}
};
From the std::array
documentation, in the constructor's section, we can read:
initializes the array following the rules of aggregate initialization (note that default initialization may result in indeterminate values for non-class T)
emphasis mine
In your case, you have a std::array<int, 4>
. int
matches the definition of a non-class type so the default initialization will let the data_
member contents with indeterminate values.
If you had initialized the data_
member as:
std::array<int, 4> data_ {}; // Note the braces
The elements would have been value-initialized which would lead to zero-initialization for int
elements.
Edit (from comments):
std::variant::emplace()
forwards its arguments but since you did not have provided any argument for the emplaced std::array<int, 4>
, your std::variant
will hold a value-initialized std::array<int, 4>
so the underlying int
elements will be zero-initialized.
Since you want the second use-case and you want the array contents to remain uninitialized, you can of course do what you suggested:
struct X
{
std::array<int, 4> data_;
X()
{}
};
struct Y
{
std::variant<X, /*...*/> data_ {};
Y()
{
data_.emplace<X>();
}
};
But you need to take care that the array contents will not be accidentally accessed before it is later on properly initialized.
Edit:
To initialize the std::array
afterwards, you should make sure that it is performed through a reference and not a copy of the array (in order to avoid undefined behaviour by copying uninitialized data).
For example:
Y y;
//X x = std::get<X>(y); // Wrong
X & x = std::get<X>(y); // Right
x.data_[0] = 42;
x.data_[1] = 422;
x.data_[2] = 442;
x.data_[3] = 4422;