Элемент массива с нулевой инициализацией в списке инициализации

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

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

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

int myArray[10] = {};

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

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

в скобки:

public:
    X()
    : m_array()
    {}

в фигурные скобки:

public:
    X()
    : m_array{}
    {}

как правильно? Есть ли разница между ними в C++11?

3 ответов


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

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

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

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

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

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


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

public:
    X()
    : m_array()
    {}

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

public:
    X()
    : m_array{}
    {}

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


чтобы дать более полный ответ, давайте рассмотрим §8.5 из N4140.

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

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

  1. до ноль-инициализировать объект или ссылка типа T означает:

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

  2. до значение-инициализировать объект типа T означает:

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

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

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

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

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

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

§8.5.4:

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

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

и обратно в §8.5.1:

  1. если их меньше инициализатор-п. в списке, чем есть несколько членов в совокупности, то каждый член явно не инициализированный должен быть инициализирован из его brace-or-equal-initializer или, если нет brace-or-equal-initializer, из пустого список инициализации (8.5.4).

и мы заканчиваем §8.5.4 опять:

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

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

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

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

cppreference:

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


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