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
Xis default-inserted if it is initialized by evaluation of the expressionallocator_traits<A>::construct(m, p)where
pis 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
Tmeans:
- if
Tis 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
Tis 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
Tis 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