Инициализация по умолчанию std :: array?

104

В C ++ 11 std::arrayесть ли у меня гарантия, что синтаксис std::array<T, N> x;инициализирует все элементы массива по умолчанию?

РЕДАКТИРОВАТЬ : если нет, существует ли синтаксис, который будет работать со всеми массивами (включая массивы нулевого размера) для инициализации всех элементов их значением по умолчанию?

РЕДАКТИРОВАТЬ : в cppreference в описании конструктора по умолчанию говорится:

(constructor) (implicitly declared) (public member function)
default-constructs or copy-constructs every element of the array 

так что ответ может быть положительным. Но я хотел бы быть уверенным в этом согласно стандарту или будущему стандарту.

Винсент
источник
Не думаю. Он объявлен по умолчанию, поэтому в основном эквивалентен T x[N]синтаксису.
Rapptz

Ответы:

149

По определению инициализация по умолчанию - это инициализация, которая происходит, когда не указана другая инициализация; язык C ++ гарантирует вам, что любой объект, для которого вы не предоставили явный инициализатор, будет инициализирован по умолчанию (C ++ 11 §8.5 / 11). Сюда входят объекты типа std::array<T, N>и T[N].

Имейте в виду, что существуют типы, для которых инициализация по умолчанию не имеет эффекта и оставляет значение объекта неопределенным: любой неклассовый, не-массивный тип (§8.5 / 6). Следовательно, инициализированный по умолчанию массив объектов с такими типами будет иметь неопределенное значение, например:

int plain_int;
int c_style_array[13];
std::array<int, 13> cxx_style_array;

Оба массива в стиле c и std::arrayзаполнены целыми числами неопределенного значения, так же как и plain_intимеют неопределенное значение.

Есть ли синтаксис, который будет работать со всеми массивами (включая массивы нулевого размера) для инициализации всех элементов их значением по умолчанию?

Я предполагаю, что когда вы говорите «к их значению по умолчанию», вы действительно имеете в виду «инициализировать все элементы T{}». Это не инициализация по умолчанию , это инициализация значения (8.5 / 7). Вы можете довольно легко запросить инициализацию значения в C ++ 11, задав каждому объявлению пустой инициализатор:

int plain_int{};
int c_style_array[13]{};
std::array<int, 13> cxx_style_array{};

Это по очереди инициализирует значение всех элементов массива, в результате чего plain_old_intвсе члены обоих типов массивов будут инициализированы нулем.

Кейси
источник
А если это член класса: struct X {std :: array <int, 12> dozen; X (): dozen () {} Это принесет мне двенадцать нулей?
Gerardw
4
@gerardw По стандарту да. Остерегайтесь ошибок в MSVC, он не может правильно реализовать некоторые случаи инициализации значений.
Кейси
1
действительно, boost говорит так и обходится с их boost::value_initialized ссылкой, но я считаю, что VC12 (VS2013) теперь имеет гораздо лучшую поддержку.
v.oddou 04
1
Заставляет меня пожелать, чтобы комитет изменил стандарт на инициализацию значения по умолчанию и подорвал значение по запросу. Т.е. std :: array <int, 12> = {std :: undefined}; или что-то в этом роде
Виктор
На практике что вообще означает инициализировать что-то неопределенным значением? Какая альтернатива?
Эндрю
21

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

Описание на cppreference.com на самом деле немного вводит в заблуждение. std::arrayявляется агрегатным классом, и если тип элемента является примитивным, это POD: «простые старые данные» с семантикой, близкой к языку C. Неявно определенный конструктор std::array< int, N >является тривиальным один , который абсолютно ничего не делает.

Синтаксис, подобный std::array< int, 3 >()или, std::array< int, 3 > x{}который предоставляет обнуленные значения, не делает этого путем вызова конструктора. Получение нулей является частью инициализации значения , указанной в C ++ 11 §8.5 / 8:

Инициализировать значение объекта типа T означает:

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

std::arrayне имеет конструктора по умолчанию, предоставляемого пользователем, поэтому он инициализируется нулем. Он имеет неявно определенный конструктор по умолчанию, но он тривиален, поэтому он никогда не инициализируется по умолчанию. (Но это не имеет значения, поскольку тривиальная инициализация по определению не имеет никакого эффекта во время выполнения.)

если нет, существует ли синтаксис, который будет работать со всеми массивами (включая массивы нулевого размера) для инициализации всех элементов их значениями по умолчанию?

Массивы в стиле C и std::arrayоба являются агрегатами, и способ полной инициализации нулями любого агрегата - это синтаксис = {}. Это работает с C ++ 98. Обратите внимание, что массивы в стиле C не могут иметь нулевой экстент, и sizeof (std::array< X, 0 >)он не равен нулю.

Potatoswatter
источник
6

Оба T x[N];и по std::array<T, N> x;умолчанию инициализируют каждый элемент массива.

Например, если T = std::stringкаждый элемент будет пустой строкой. Если Tэто класс без конструктора по умолчанию, оба не будут скомпилированы. Если T = intкаждый элемент будет иметь неопределенное значение (если это объявление не находится в области пространства имен)

Cubbi
источник
0

Прежде всего, T x [N] по умолчанию инициализирует элементы, хотя инициализация по умолчанию скалярного типа T фактически ничего не делает. Вышеупомянутое также справедливо для std :: array x. Думаю, вам нужна инициализация списка.

Линси
источник