Is a structure container containing a primitive type zero initialized?

#include <vector> struct S { int x; }; std::vector<S> v; int main() { v.resize(1000); return v[42].x; } 

Is the above program a guarantee of returning 0 in C ++ 14? Why?

+7
c ++ c ++ 14
source share
2 answers

Yes, since std::vector::resize and similar methods initialize the default † which in turn value initializes the elements of aggregates:

From cppr:

Value initialization effects:
[...]
if T is a class type with a default constructor that is neither provided by the user nor deleted (i.e., it can be a class with an implicit or standard default constructor), the object is initialized to zero, and then by default it is initialized if it has a non-trivial default constructor;

and Zero Initialiation does what we need:

If T is a type of non-unit class, all base classes and non-static data elements are initialized to zero, and all additions are complemented by zero bits. Constructors, if any, are ignored.

And of course, zero initialization of our member does the right thing:

If T is a scalar type, the initial value of the object is the integral constant zero, explicitly converted to T.


† Dispenser is used by default; custom dispensers can use different initialization. You can use them to leave these values ​​unified; see the full article on default-insert .

+3
source share

Is the above program a guarantee of returning 0 in C ++ 14? Why?

Yes. From [vector.capacity]:

void resize(size_type sz);
13 Effects: If sz < size() , erases the last size() - sz elements from the sequence. Otherwise, add sz - size() to the default elements added to the sequence.

Where, from [container.requirements.general]:

An element X set by default if it is initialized by evaluating the expression allocator_traits<A>::construct(m, p) , where p is the uninitialized storage address for the element allocated in X

construct for std::allocator<T> does, from [default.allocator]:

 template <class U, class... Args> void construct(U* p, Args&&... args); 

Effects: ::new((void *)p) U(std::forward<Args>(args)...)

So this is initialization of values. We are doing new S() , not new S , so member X will be initialized to zero.


Ways to avoid this behavior (if desired):

  • Change the distributor. Provide your own type of dispenser that has two overloads for construct : one empty (which will do the initialization by default) and one accepts Args&&...
  • Change the type. Add a default constructor to S that does not initialize.
+3
source share

All Articles