In C++, when I have a struct like
struct myStruct
{
int i;
bool b;
MyClass *myobj;
};
and I then make a vector of this
std::vector<myStruct> myVector;
and I resize the vector with
myVector.resize(10);
Will the struct's members be initialized with zero's (including the pointer)? Can I not assume that and might there be random data in the struct's members?
In this particular case, the answer is YES because of std::vector::resize()
's properties:
If the current size is less than count, additional elements are appended and initialized with copies of value. (until C++11)
If the current size is less than count, (since C++11)
1) additional value-initialized elements are appended
2) additional copies of value are appended
The answer will be NO for normal cases, e.g. myStruct s
, this will leave them (s.i, s.bool, s.myobj
) with indeterminate values.
If you still want them to be initialized as expected, create a constructor for the struct:
struct myStruct {
int i;
bool b;
MyClass *myobj;
myStruct():i(0),b(false),myobj(NULL) { } // <- set them here by default
};
I actually beg to differ. In this particular case, the standard appears to guarantee that the objects will be zero-initialized. (All standard references below are to N3936.)
vector::resize
in this case is specified to append 10 "default-inserted elements to the sequence" (§23.3.6.3 [vector.capacity]/p12).
Default-insertion is in turn defined as (§23.2.1 [container.requirements.general]/p14; X
is the container's type; m
is an lvalue of type A
, which is the container's allocator_type
):
An element of
X
is default-inserted if it is initialized by evaluation of the expressionallocator_traits<A>::construct(m, p)
where
p
is the address of the uninitialized storage for the element allocated withinX
.
Since as written the code uses the default allocator, the allocator_traits::construct
call simply calls construct(p)
on an instance of std::allocator<myStruct>
(§20.7.8.2 [allocator.traits.members]/p5), which is specified as (§20.7.9.1 [allocator.members]/p12)
template <class U, class... Args> void construct(U* p, Args&&... args);
12 Effects:
::new((void *)p) U(std::forward<Args>(args)...)
Since the parameter pack is empty for construct(p)
, the effect of the construct()
call is::new((void *)p) myStruct()
.
The standard provides that new-initializers, like the ()
in the placement new expression above, are to be interpreted "according to the initialization rules of 8.5 for direct initialization" (§5.3.4 [expr.new]/p17). In turn, §8.5 [dcl.init]/p11 specifies that "An object whose initializer is an empty set of parentheses, i.e., ()
, shall be value-initialized."
Value-initialization is specified as (§8.5 [dcl.init]/p8)
To value-initialize an object of type
T
means:
- if
T
is a (possibly cv-qualified) class type (Clause 9) with either no default constructor (12.1) or a default constructor that is user-provided or deleted, then the object is default-initialized;- if
T
is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;- if
T
is an array type, then each element is value-initialized;- otherwise, the object is zero-initialized.
In this case, myStruct
is a "class type without a user-provided or deleted default constructor", which means it matches the second bullet point, which performs zero-initialization. Thus, value-initialization for an object of type myStruct
means the object will be zero-initialized.
However, note that the rules here are quite convoluted, and the path to automatic zero-initialization is quite fragile. For example, if you give myStruct
a default constructor like myStruct() { }
, then that's a user-provided default constructor, which means that it will match the first bullet point for value initialization instead of the second, which in turn means that it won't be zero-initialized. Moreover, this may also not work if your vector
uses a custom allocator, as its construct()
might have different semantics than that of the default allocator.
Therefore, it is probably better to give myStruct
a default constructor that explicitly zeroes its members.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With