Подтвердить что ты не робот

Элемент массива Zero-Initialize в списке инициализации

У меня есть класс с членом массива, который я бы хотел инициализировать для всех нулей.

class X
{
private:
    int m_array[10];
};

Для локальной переменной существует простой способ инициализации нуля (см. здесь):

int myArray[10] = {};

Кроме того, член класса m_array явно должен быть инициализирован, поскольку инициализируемые по умолчанию ints просто оставят случайный мусор, как описано здесь.

Однако я могу видеть два способа сделать это для массива-члена:

С круглыми скобками:

public:
    X()
    : m_array()
    {}

С фигурными скобками:

public:
    X()
    : m_array{}
    {}

Правильны ли они? Есть ли разница между двумя в С++ 11?

4b9b3361

Ответ 1

Инициализация любого члена с помощью () выполняет инициализацию значения.

Инициализация любого типа класса конструктором по умолчанию с помощью {} выполняет инициализацию значения.

Инициализация любого другого агрегатного типа (включая массивы) с помощью {} выполняет инициализацию списка и эквивалентна инициализации каждого из членов агрегата с помощью {}.

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

Инициализация любого другого типа с помощью {} выполняет инициализацию значения.

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

Ответ 2

Типы инициализации могут быть довольно утомительными, но в этом случае это тривиально. Для:

public:
    X()
    : m_array()
    {}

так как список выражений между круглыми скобками пуст, происходит инициализация значения. Аналогично для:

public:
    X()
    : m_array{}
    {}
Выполняется инициализация списка

а затем инициализация значения, так как список init-списка пуст.


Чтобы дать более полный ответ, переходите к §8.5 из N4140.

  1. Если для объекта не задан инициализатор, объект по умолчанию инициализируется. При хранении для объекта с автоматическим или динамическая длительность хранения, объект имеет неопределенный значение, и если для объекта не выполняется инициализация, это объект сохраняет неопределенное значение до тех пор, пока это значение не будет заменено (5,17).

Это неопределенное значение - это то, что вы называете значениями мусора.

  1. Для нулевой инициализации объекта или ссылки типа T означает:

    - если T - тип массива, каждый элемент инициализируется нулем

  2. Для инициализации значения объекта типа T означает:

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

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

    - в противном случае объект инициализируется нулем.

  3. Семантика инициализаторов следующая.... - Если инициализатор представляет собой (не заключенный в скобки) бит-init-list, объект или ссылка инициализируется по списку (8.5.4).

    - Если инициализатор is(), объект инициализируется значением.

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

§8.5.4:

  1. Список-инициализация объекта или ссылки типа T определяется следующим образом:

    - Если T является агрегатом, выполняется агрегатная инициализация (8.5.1).

И вернемся к §8.5.1:

  1. Если в списке меньше предложений инициализатора, чем являются членами в совокупности, то каждый член явно не инициализируется инициализируется из его логического или равного-инициализатора или, если нет элемента с выравниванием или равным-инициализатором, из пустого список инициализаторов (8.5.4).

И снова мы закончим с §8.5.4:

  1. Список-инициализация объекта или ссылки типа T определяется следующим образом:

    - В противном случае, если в списке инициализаторов нет элементов, объект инициализируется значением.

Так как перемещение (черновик) стандарта может занять у вас дыхание, я рекомендую cppreference, так как он сильно нарушает его.

Соответствующие ссылки:

cppreference:

Проект стандарта:

Ответ 3

Круглые скобки работают на С++ 98 и вызывают нулевую инициализацию, что вам и нужно. Я проверял gcc 4.3. Изменить: удалить неверную инструкцию о С++ 11. Я также подтвердил, что пустые фигурные скобки выполняют инициализацию с пустым списком, используя clang 3.4 с -std = С++ 11.