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