Элемент массива Zero-Initialize в списке инициализации
У меня есть класс с членом массива, который я бы хотел инициализировать для всех нулей.
class X
{
private:
int m_array[10];
};
Для локальной переменной существует простой способ инициализации нуля (см. здесь):
int myArray[10] = {};
Кроме того, член класса m_array
явно должен быть инициализирован, поскольку инициализируемые по умолчанию ints просто оставят случайный мусор, как описано здесь.
Однако я могу видеть два способа сделать это для массива-члена:
С круглыми скобками:
public:
X()
: m_array()
{}
С фигурными скобками:
public:
X()
: m_array{}
{}
Правильны ли они? Есть ли разница между двумя в С++ 11?
Ответы
Ответ 1
Инициализация любого члена с помощью ()
выполняет инициализацию значения.
Инициализация любого типа класса конструктором по умолчанию с помощью {}
выполняет инициализацию значения.
Инициализация любого другого агрегатного типа (включая массивы) с помощью {}
выполняет инициализацию списка и эквивалентна инициализации каждого из членов агрегата с помощью {}
.
Инициализация любого ссылочного типа с помощью {}
создает временный объект, который инициализируется из {}
и привязывает ссылку к этому временному.
Инициализация любого другого типа с помощью {}
выполняет инициализацию значения.
Следовательно, для почти всех типов инициализация из {}
даст тот же результат, что и инициализация значения. У вас не может быть массивов ссылок, поэтому они не могут быть исключением. Возможно, вы сможете создавать массивы типов агрегатных классов без конструктора по умолчанию, но компиляторы не согласны с точными правилами. Но чтобы вернуться к вашему вопросу, все эти угловые случаи для вас не имеют особого значения: для вашего конкретного типа элемента массива они имеют точно такой же эффект.
Ответ 2
Типы инициализации могут быть довольно утомительными, но в этом случае это тривиально. Для:
public:
X()
: m_array()
{}
так как список выражений между круглыми скобками пуст, происходит инициализация значения. Аналогично для:
public:
X()
: m_array{}
{}
Выполняется инициализация списка а затем инициализация значения, так как список init-списка пуст.
Чтобы дать более полный ответ, переходите к §8.5 из N4140.
- Если для объекта не задан инициализатор, объект по умолчанию инициализируется. При хранении для объекта с автоматическим или динамическая длительность хранения, объект имеет неопределенный значение, и если для объекта не выполняется инициализация, это объект сохраняет неопределенное значение до тех пор, пока это значение не будет заменено (5,17).
Это неопределенное значение - это то, что вы называете значениями мусора.
-
Для нулевой инициализации объекта или ссылки типа T
означает:
- если T - тип массива, каждый элемент инициализируется нулем
-
Для инициализации значения объекта типа T
означает:
- если T является (возможно, cv-квалифицированным) классом типа... тогда объект инициализируется по умолчанию;...
- если T - тип массива, то каждый элемент инициализируется значением;
- в противном случае объект инициализируется нулем.
-
Семантика инициализаторов следующая.... - Если инициализатор представляет собой (не заключенный в скобки) бит-init-list, объект или ссылка инициализируется по списку (8.5.4).
- Если инициализатор is(), объект инициализируется значением.
Пока ясно, что инициализация значения сделает каждый элемент массива нулевым, так как int
не является типом класса. Но мы еще не рассмотрели инициализацию списка и агрегатную инициализацию, так как массив является агрегатом.
§8.5.4:
-
Список-инициализация объекта или ссылки типа T
определяется следующим образом:
- Если T является агрегатом, выполняется агрегатная инициализация (8.5.1).
И вернемся к §8.5.1:
- Если в списке меньше предложений инициализатора, чем являются членами в совокупности, то каждый член явно не инициализируется инициализируется из его логического или равного-инициализатора или, если нет элемента с выравниванием или равным-инициализатором, из пустого список инициализаторов (8.5.4).
И снова мы закончим с §8.5.4:
-
Список-инициализация объекта или ссылки типа T
определяется следующим образом:
- В противном случае, если в списке инициализаторов нет элементов, объект инициализируется значением.
Так как перемещение (черновик) стандарта может занять у вас дыхание, я рекомендую cppreference, так как он сильно нарушает его.
Соответствующие ссылки:
cppreference:
Проект стандарта:
Ответ 3
Круглые скобки работают на С++ 98 и вызывают нулевую инициализацию, что вам и нужно. Я проверял gcc 4.3. Изменить: удалить неверную инструкцию о С++ 11. Я также подтвердил, что пустые фигурные скобки выполняют инициализацию с пустым списком, используя clang 3.4 с -std = С++ 11.