Будет ли сгенерированный компилятором конструктор по умолчанию инициализировать указатели в std :: array на nullptr? - PullRequest
1 голос
/ 27 апреля 2019

Правильно ли, что с учетом приведенного ниже кода компилятор должен сгенерировать Node(), который должен вызвать std::array<Node *, 100>(), который должен инициализировать все 100 указателей на nullptr.

Примечание: я знаю, что могу это сделать, если использую std::array<Node *, 100> children {};, но я не пытаюсь заставить мой код работать (он уже работает), я пытаюсь убедиться, что он не работает случайно .

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

Обновление:

Здесь указатели - мусор:

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

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

Здесь указатели nullptr:

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

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

Пожалуйста, поправьте меня, если я ошибаюсь.

Ответы [ 3 ]

5 голосов
/ 27 апреля 2019

Цитировать cppreference в конструкторе std::array:

инициализирует массив, следуя правилам агрегатной инициализации (обратите внимание, что инициализация по умолчанию может привести к неопределенным значениям для не класса T)

Объявляя вашу переменную как std::array<Node *, 100> children;, вы вызываете конструктор по умолчанию. И, согласно правилам инициализации, POD (int, char, double, указатели, ...) не инициализируются по умолчанию. Так что нет, ваш массив не будет инициализирован с nullptr, если вы не используете агрегатную инициализацию.

Совокупная инициализация

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

вызывает конструктор по умолчанию, но агрегатный инициализатор не дается, поэтому агрегатная инициализация не произойдет. Тем не менее

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

не только вызывает конструктор по умолчанию, но также выполняет агрегатную инициализацию. В этом случае совокупность {} просто пуста. И, следуя правилам агрегатной инициализации, если инициализаторов меньше, чем элементов данных, каждый неинициализированный элемент будет инициализирован по умолчанию. Итак

Node x;
std::array<Node *, 100> children = {&x};
Например,

инициализирует первый элемент массива указателем на x, и каждый последующий элемент будет по умолчанию инициализирован на nullptr.

1 голос
/ 27 апреля 2019

Согласно этому ответу , инициализация по умолчанию std::array указателей будет не инициализировать содержащиеся в нем указатели, и их значения будут неопределенными.

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

Однако вы можете использовать значение инициализации, чтобы инициализировать все содержащиеся в нем указатели на nullptr. На std::array это приводит к тому, что значение инициализирует каждое значение в массиве, что, в свою очередь, инициализирует каждый указатель нулями.

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

В списке инициализатора члена вы также можете сделать это следующим образом:

Node::Node() : children{/* value init array */} {/* empty c'tor body */}
0 голосов
/ 27 апреля 2019

Пока указателю не присвоено значение, он по умолчанию указывает на «мусорный» адрес. Компилятор не назначает им значение по умолчанию nullptr. Фактически, он не присваивает указателям никакого значения по умолчанию.
Edit:
Из документации cppreference для std :: array :

обратите внимание, что инициализация по умолчанию может привести к неопределенным значениям для не-класса T

Так что, если вы используете конструктор по умолчанию, вам нужно присвоить каждому элементу значение nullptr.

...