2

Is it correct that given the code below, the compiler should generate Node() which should call std::array<Node *, 100>() which should initialize all 100 pointers to nullptr.

Side note: I know that I can make that happen if I use std::array<Node *, 100> children {};, but I am not trying to get my code to work (it already does), I am trying to make sure that it's not working by accident.

struct Node
{
    int value;
    std::array<Node *, 100> children;
}

Update:

Here pointers are garbage:

struct Node
{
    int value;
    std::array<Node *, 100> children;
}

struct Node
{
    Node() : children() {}
    int value;
    std::array<Node *, 100> children;
}

Here pointers are nullptr:

struct Node
{
    int value;
    std::array<Node *, 100> children {};
}

struct Node
{
    Node() : children{} {}
    int value;
    std::array<Node *, 100> children;
}

Please, correct me if I am wrong.

Martin F
  • 171
  • 1
  • 1
  • 10
  • What you want is to use `shared_ptr` instead of bare pointers. Way less surprises in the end as long as you use them everywhere (consistently). – Alexis Wilke Apr 28 '19 at 03:16

3 Answers3

5

To quote cppreference on the constructor of std::array:

initializes the array following the rules of aggregate initialization (note that default initialization may result in indeterminate values for non-class T)

By declaring your variable like std::array<Node *, 100> children; you invoke the default constructor. And, according to the rules of initialization, PODs (int, char, double, pointers, ...) are not default initialized. So no, your array will not be initialized with nullptr if you don't use aggregate initialization.

Aggregate initialization

std::array<Node *, 100> children;

invokes the default constructor, but no aggregate initializer is given so aggregate initialization won't happen. However

std::array<Node *, 100> children{}
std::array<Node *, 100> children = {};

not only invokes the default constructor, but also performs an aggregate initialization. In this case, the aggregate {} is just empty. And, following the rules of aggregate initialization, if there are less initializers than data members, every uninitialized member will be default initialized. So

Node x;
std::array<Node *, 100> children = {&x};

for example, will initialize the first array element with the pointer to x and every successive element will be default initialized to nullptr.

Timo
  • 9,269
  • 2
  • 28
  • 58
  • 1
    I would add clarification: No, the array will not be initialised with nullptr *if `Node` is default initialised*. – eerorika Apr 27 '19 at 18:47
  • Some of the terminology is lost on me... `std::array children {};` will initialize all 100 pointers to nullptr according to this: https://stackoverflow.com/questions/35849693/c11-how-to-initialize-array-of-pointers-of-some-class-with-nullptr Does that mean that `Node() : children() {}` doesn't do that, but `Node() : children{} {}` would? – Martin F Apr 27 '19 at 18:50
  • Amazing, it's very clean now. Thank you! – Martin F Apr 27 '19 at 19:02
2

According to this answer, default initialization of a std::array of pointers will not initialize the pointers it contains, and their values will be indeterminate.

std::array<Node *, 100> children; // pointers are uninitialized

You can however use value initialization to initialize all the contained pointers to nullptr. On a std::array, this has the effect of value initializing each value in the array, which in turn zero-initializes every pointer.

std::array<Node *, 100> children {}; // pointers are all null

In a member initializer list, you can also do this as follows:

Node::Node() : children{/* value init array */} {/* empty c'tor body */}
alter_igel
  • 6,899
  • 3
  • 21
  • 40
0

Until a pointer is assigned a value, it points to a "garbage" address by default. The compiler does not assign them a default value of nullptr. In fact, it does not assign any "default" value to pointers.
Edit:
From the cppreference documentation for std::array:

note that default initialization may result in indeterminate values for non-class T

So if you use the default constructor, you need to assign each element a value of nullptr yourself.

Pierce Griffiths
  • 733
  • 3
  • 15