Are the members of structs in a null-initialized vector in C ++?

In C ++, when I have a structure like

struct myStruct
{
  int i;
  bool b;
  MyClass *myobj;
};

      

and then make a vector of this

std::vector<myStruct> myVector;

      

and I resize the vector with

myVector.resize(10);

      

Will the members of the structure be initialized to zero (including the pointer)? Can I assume that and could there be random data in structure members?

+3


source to share


5 answers


In this particular case the answer is YES because of the std::vector::resize()

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 would be NO for normal cases, for example. myStruct s

, this will leave them ( s.i, s.bool, s.myobj

) with undefined 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
};

      

+5


source


I really ask you to distinguish. In this particular case, the standard guarantees that objects will be zero-initialized. (All standard references below are to N3936.)

vector::resize

in this case it is specified to add 10 "default inserted elements to the sequence" (§23.3.6.3 [vector.capacity] / p12).

The default insert, in turn, is defined as (§23.2.1 [container.requirements.general] / p14; X

is the type of the container; m

is the value of the type A

that is the container allocator_type

):

An element is X

set by default if it is initialized by evaluating an expression

allocator_traits<A>::construct(m, p)

      

where p

is the address of the uninitialized storage for the item allocated in X

.

Since the code text uses the default allocator , the call allocator_traits::construct

simply calls construct(p)

on an instance 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 call effect construct()

::new((void *)p) myStruct()

.



The standard stipulates that new initializers, such as ()

in a new placement expression, must be interpreted "according to 8.5 initialization rules for direct initialization" (§5.3.4 [expr.new] / p17). In turn, §8.5 [dcl.init] / p11 indicates that "An object whose initializer is an empty set of parentheses, that is ()

, must be value-initialized."

Value initialization is specified as (§8.5 [dcl.init] / p8)

To value-initialize an object of type T

means:

  • if it T

    is (possibly cv-qualit) a class type (section 9) without a default constructor (12.1) or a default constructor that is user supplied or remote, then the object is default initialized;
  • if T

    is a (possibly cv-qualified) class type with no user-supplied or remote default constructor, then the object is initialized to zero and 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 initialized to zero.

In this case, it myStruct

is a "class type with no user-supplied or removable default constructor", which means that it corresponds to a second bullet point that performs null initialization. So value initialization for an object of type myStruct

means that the object will be initialized to zero.

Note, however, that the rules are rather convoluted and the path to automatic null initialization is rather fragile. For example, if you give a myStruct

default constructor such as myStruct() { }

, then it is a user supplied default constructor, which means it will match the first bullet point to initialize the value instead of the second, which in turn means it will not be zero initialized ... Moreover, it may also not work if yours vector

uses a custom allocator, as it construct()

may have different semantics than the default allocator.

So it's probably best to give a myStruct

default constructor that explicitly zeroes out its elements.

+4


source


Yes, structures will be initialized to zero IN THIS BASIC case. The reason is the implementation of the method resize()

in STL. New elements are built by default:

void resize(size_type __new_size) {
    resize(__new_size, value_type());
}

      

value_type()

results in null initialization.

evidence

#include <cstdio>

struct foo {
  int i;
  int j;
  void *k;
};

void test(const foo& fooinst) {
  printf("%d\n",fooinst.i);
}

main() {
  test(foo());
}

      

Here's the relevant part of the resulting g ++ disassembly. Note the explicit null initialization of structure members before calling.

test.cpp      ****   test(foo());
  56                            .loc 1 14 0
  57 002d C745F000              movl    $0, -16(%rbp)
  57      000000
  58 0034 C745F400              movl    $0, -12(%rbp)
  58      000000
  59 003b 48C745F8              movq    $0, -8(%rbp)
  59      00000000 
  60 0043 488D45F0              leaq    -16(%rbp), %rax
  61 0047 4889C7                movq    %rax, %rdi
  62 004a E8000000              call    _Z4testRK3foo

      

+2


source


The values ​​in are vector

initialized by the default constructor (or initialized value) struct

, in this case myStruct

.

struct

has no default constructor, so a generated compiler will be created. In this case, the objects are myStruct

not initialized.

No, in general, you cannot assume that the data will be zero-initialized.

This particular case ( .resize()

) chooses in a situation where there is value initialization and there have been some changes from C ++ 03 and C ++ 11 (other answers in more detail).

The best advice left to do is add a default constructor that initializes correctly struct

.

+1


source


The ctor for the struct is called. Since you don't specify one (and you can even for a struct), the default is do-nothing ctor. By default, ctor does not clear items.

0


source







All Articles