Initialize a std::vector of structures to zero - c++

I am guaranteed to initialize a vector of struct with each element initialized to zero with that code ?
#include <vector>
struct A {
int a, b;
float f;
};
int main()
{
// 100 A's initialized to zero (a=0, b=0, f=0.0)
// std::vector<A> my_vector(100, {}); does not compile
std::vector<A> my_vector(100, A{});
}

Short answer : Yes
To know how refer below :
when you write
std::vector<A> my_vector(...)
you are doing value initialization if the parentheses are empty, or direct initialization if non-empty.
and when you write A{} you are doing list initialization which implies value initialization if the braces are empty, or aggregate initialization if the initialized object is an aggregate.
as your parentheses are non-empty so below code
std::vector<A> my_vector(100, A{});
is interpreted as
std::vector<A> my_vector(/*created vector of 100 elements */ 100, /* by list Initialization of struct with default values*/A{});
As A{} is empty in this case you are doing value initialization which is leading to zero_initialization
as
As part of value-initialization sequence for non-class types and for members of value-initialized class types that have no constructors, including value initialization of elements of aggregates for which no initializers are provided.

Yes it is guaranteed since A{} is value initialization and from cppreference:
Zero initialization is performed in the following situations:
As part of value-initialization sequence for non-class types and for members of value-initialized class types that have no constructors, including value initialization of elements of aggregates for which no initializers are provided.
You can also use:
std::vector<A> my_vector(100, {0,0,0});

Yes, you are guaranteed to have zero initialization with that code

Related

Is a float member guaranteed to be zero initialized with {} syntax?

In C++17, consider a case where S is a struct with a deleted default constructor and a float member, when S is initialized with empty braces, is the float member guaranteed by the standard to be zero-initialized?
struct A {
int x{};
};
struct S
{
S() = delete;
A a;
float b;
};
int main()
{
auto s = S{}; // Is s.b guaranteed to be zero?
}
In my opinion, cppreference.com is not clear, saying both that:
If the number of initializer clauses is less than the number of members and basesor initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C++14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
(from here), which implies that b is guaranteed to be zero
In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.
(from here)
which implies that b is not guaranteed to be zero.
There is also a discussion that seems to imply that while not guaranteed, all known compiler zero-initialize anyway:
The standard specifies that zero-initialization is not performed when the class has a user-provided or deleted default constructor, even if that default constructor is not selected by overload resolution. All known compilers performs additional zero-initialization if a non-deleted defaulted default constructor is selected.
Related to Why does aggregate initialization not work anymore since C++20 if a constructor is explicitly defaulted or deleted?
This is a quirk of C++ that is fixed in C++20. In the meantime you can add explicit to the deleted default constructor to force the struct to become non-aggregate, and make your code a guaranteed compile error:
struct A {
int x{};
};
struct S
{
explicit S() = delete;
const A a;
const float b;
};
int main()
{
auto s = S{}; // error: call to deleted constructor of 'S'
}
Because S is an aggregate, S{} will perform aggregate initialization. The rule in the standard about how members are initialized when there are no initializers in the list is basically what you cited:
If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
So for b, that's the equivalent of float b = {};. Per the rules of list initialization, we have to get all the way down to 3.10:
Otherwise, if the initializer list has no elements, the object is value-initialized.
And value initialization will initialize a float to 0.

C++ zero initialization without constructor

I don't understand what happens regarding the zero initialization of structs that has default values for its members.
If I have these structs:
struct A {
int *a;
int b;
};
struct B {
int *a;
int b;
B() : b(3) {}
};
struct C {
int *a;
int b = 3;
};
What we can say without a doubt is:
A a; leaves all fields uninitialized
A a{}; is {nullptr, 0}
B b; and B b{}; both are {garbage, 3} (the constructor is called)
Now it's unclear what happens when I do the following, here are the results using gcc:
C c; // {garbage, 3}
C c{}; // {nullptr, 3}
The question is: does C c{}; guarantees that C::a is initialized to nullptr, in other words, does having default members like in C still zero initialize the other members if I explicitly construct the object like C c{};?
Because it's not what happens if I have a constructor that does the same thing than C (like in B), the other members are not zero initialized, but why? What is the difference between B and C?
As of C++14, C is an aggregate (like A), and C c{} syntax performs aggregate initialization. This includes, in part:
[dcl.init.aggr]/8 If there are fewer initializer-clauses in the list than there are elements in a non-union aggregate, then each element not explicitly initialized is initialized as follows:
(8.1) — If the element has a default member initializer (12.2), the element is initialized from that initializer.
(8.2) — Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list (11.6.4).
(8.3) — Otherwise, the program is ill-formed.
So C c{}; is equivalent to C c{{}, 3};. Initializing an int* member with empty list causes it to be zero-initialized.
In C++11, C is not an aggregate (having a default member initializer was disqualifying), and C c{}; calls an implicitly-defined constructor that leaves c.a member uninitialized.
In all versions of the standard, B is not an aggregate due to the user-defined constructor. B b{}; calls that constructor, which explicitly initializes b member and chooses to leave a uninitialized.
Aggregate initialization - cppreference.com
If the number of initializer clauses is less than the number of members or initializer list is completely empty, the remaining members are value-initialized. If a member of a reference type is one of these remaining members, the program is ill-formed.
(until C++11)
If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default member initializers, if provided in the class definition, and otherwise (since C++14) copy-initialized from empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
(since C++11)
So A a{}; all members are default initialized

Value-initializing std::array member?

Let's suppose I have a class template that has a std::array member:
template<typename T>
class C {
public:
C();
private:
std::array<T, 42> a;
};
How do I define C::C such that a will always be value-initialized (not default-initialized)? ie such that the constructor calls T() to initialize every element of a - and that, for example, if T is int, then every element of a is guaranteed to be zero and not an indeterminant value?
int main() {
C<int> c;
assert(c.a[13] == 0); // ignoring private for exposition
}
UPDATE
Additional information for posterity:
std::array is an aggregate type with a single element T[N]
Initialization of std::array by an init-list is aggregate initialization
Aggregate initialization with an empty init-list causes each element to not be explicitly initialized. Such elements are initialized as if by copy-initialization from an empty init-list.
The array T[N] is therefore copy-initialized from an empty init-list. It is also an aggregate therefore 2 and 3 apply recursively.
Each of the N elements of T[N] are copy-initialized from an empty init-list.
Each T object is copy-list-initialized with an empty init-list as per [dcl.init.list]/3. The final clause of that chain is reached which reads:
Otherwise, if the initializer list has no elements, the object is value-initialized.
and voila. Initializing std::array with an empty init list {} causes its elements to be value-initialized.
You can use inline member initialization:
private:
std::array<T, 42> a{};
If you absolutely want to do it with a constructor instead (why though?) then:
C()
: a{}
{ }

initializing struct with {0}

I'm debugging some code that essentially is identical to this:
struct Foo { int a; int b; };
struct Bar { Bar() {} Foo foo{0}; };
When I make an instance of Bar, it seems like both a and b are initialized to zero. Is this guaranteed? Where can I find that in the spec?
According to cppreference.com
If the number of initializer clauses is less than the number of members [and bases (since C++17)] or initializer list is completely empty, the remaining members [and bases (since C++17)] are initialized [by their default member initializers, if provided in the class definition, and otherwise (since C++14)] by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates). If a member of a reference type is one of these remaining members, the program is ill-formed.
Foo has no default member initializers (int b{0};), so b will be initialized by list-initialization with an empty list, which means value-initialization for non-class types: b = int() // = 0.

C++ structure initialization with all zeros

In C++ if I initialize the structure in the form of "= {}", as in example below, does it ensure to assign values zero to all the member of the structure?
I understand this seem duplicate question, But my question also is if it initializes zero to all members, does it also apply for complex structure ?
Like structure within structure , or for this each member has to be explicitly assigned value zero in the code?.
typedef struct s{
int i;
bool x;
};
int main ()
{
s initial = {};
printf("%d %d", initial.i, initial.x);
}
Edit: To reference complex structure,
typedef struct scomplex{
s initial;
s t[5];
};
int main (void)
{
scomplex sc = {};
printf ("%d %d %d",sc.initial.i, sc.initial.x, sc.t[0].i);
}
But my question also is if it initializes zero to all members, does it also apply for complex structure ?
Yes, all members will be initialized, including "complex" member, but might not be initialized to zero, the final effect is determined by their types.
According to your sample code, struct s is an aggregate type, then aggregate initialization is performed.
(emphasis mine)
If the number of initializer clauses is less than the number of members and bases (since C++17) or initializer list is completely empty, the remaining members and bases (since C++17) are initialized by their default initializers, if provided in the class definition, and otherwise (since C++14) by empty lists, in accordance with the usual list-initialization rules (which performs value-initialization for non-class types and non-aggregate classes with default constructors, and aggregate initialization for aggregates).
For this case the member i and x of struct s will be value initialized to zero.
4) otherwise, the object is zero-initialized.
If struct s has any other members, they'll be initialized (value initialized or aggregate initialized according to their types) by empty lists recursively.
EDIT
For your added sample (struct scomplex), the member initial will be value initialized, and the final effect depends on the type s. And another member is an array, which will be aggregate initialized with empty list, and all the elements of the array will be value initialized; Same as member initial, the effect depends on the type s.
Problem
Will this initialize all of the members to 0?
typedef struct s{
int i;
bool x;
};
int main ()
{
s initial = {};
printf("%d %d", initial.i, initial.x);
}
Answer: yes. Proof? Here you can see it become 0.
Better Alternatives?
This is an opinionated section. But In My Opinion (IMO), initializing it with {0} would be more readable than {}, as it notifies the user of the 0. It is actually being filled up with 0's.
s initial = {0};
What is this called?
This is called Aggregate Initialization, as Dieter Lücking defined, or Value Initialization, as songyuanyao noted. It's basically a form of initialization where you can initialize a struct with values you would like. For example, let's initialize it with the value 1 instead of 0! You would do:
// Example program
#include <stdio.h>
#include <iostream>
typedef struct s{
int i;
bool x;
};
int main ()
{
s initial = {1,1};
printf("%d %d", initial.i, initial.x);
}
You can see this compiled here. As you can see above, I am doing 1,1 which is normal initialization. As opposed to 0 initialization, you can't just initialize all the parts of the struct as easily as you can with 0.
References
cpprefrence
what is aggregate initialization
What do the following phrases mean in C++: zero-, default- and value-initialization?
Glossary
Aggregate Initialization :
Aggregate initialization is a form of list-initialization, which initializes aggregates.
Value Initialization:
Initialize values
This is the initialization performed when a variable is constructed with an empty initializer.