Сводка C++11 / TL;DR
- Из-за дефекта удаления фигурной скобки примеры 0, 2, 6 не требуются для работы. Однако последние версии компиляторов реализуют предлагаемое решение для этого дефекта, так что эти примеры будут работать.
- Поскольку не указано, содержит ли
std::array
необработанный массив. Поэтому примеры 1, 3, 5, 7 не обязательны для работы. Однако я не знаю реализации стандартной библиотеки, где они не работают (на практике).
- Пример 4 всегда будет работать:
std::array<int, 3> arr4 = {1, 2, 3};
Я бы предпочел версию 4 или версию 2 (с исправлением скобок), поскольку они инициализируются напрямую и требуются/вероятно будут работать.
Для стиля AAA Саттера вы можете использовать auto arrAAA = std::array<int, 3>{1, 2, 3};
, но для этого требуется исправление исключения фигурных скобок.
std::array
должен быть агрегатом [array.overview]/2, это означает, что у него нет пользовательских конструкторов (т. е. только по умолчанию, копирование, перемещение ctor).
std::array<int, 3> arr0({1, 2, 3});
std::array<int, 3> arr1({{1, 2, 3}});
Инициализация с помощью (..)
является прямой инициализацией. Для этого требуется вызов конструктора. В случае arr0
и arr1
возможен только конструктор копирования/перемещения. Таким образом, эти два примера означают создание временного std::array
из braced-init-list и копирование/перемещение его в место назначения. Благодаря исключению копирования/перемещения компилятор может исключить эту операцию копирования/перемещения, даже если она имеет побочные эффекты.
Н.Б. даже несмотря на то, что временные объекты являются значениями prvalue, он может вызвать копию (семантически, до исключения копии), поскольку ctor перемещения std::array
может не быть объявлен неявно, например. если бы он был удален.
std::array<int, 3> arr6 = std::array<int, 3>({1, 2, 3});
std::array<int, 3> arr7 = std::array<int, 3>({{1, 2, 3}});
Это примеры инициализации копирования. Созданы два временных файла:
- через braced-init-list
{1, 2, 3}
для вызова конструктора копирования/перемещения
- через выражение
std::array<int, 3>(..)
последний временный затем копируется/перемещается в указанную переменную назначения. Создание обоих временных объектов можно исключить.
Насколько мне известно, реализация может написать конструктор explicit array(array const&) = default;
и не нарушать Стандарт; это сделало бы эти примеры неправильными. (Эта возможность исключена [container.requirements.general], слава Дэвиду Крауссу, см. это обсуждение.)
std::array<int, 3> arr2{1, 2, 3};
std::array<int, 3> arr3{{1, 2, 3}};
std::array<int, 3> arr4 = {1, 2, 3};
std::array<int, 3> arr5 = {{1, 2, 3}};
Это совокупная инициализация. Все они «напрямую» инициализируют std::array
, без вызова конструктора std::array
и без (семантического) создания временного массива. Члены std::array
инициализируются с помощью инициализации копированием (см. ниже).
На тему брекет-элизион:
В стандарте C++11 удаление фигурных скобок применяется только к объявлениям формы T x = { a };
, но не к T x { a };
. Это считается дефектом и будет исправлено в C++1y, однако предлагаемое разрешение не является частью стандарта (статус DRWP, см. верхнюю часть связанной страницы), и поэтому вы не можете рассчитывать на то, что ваш компилятор реализует его также для T x { a };
.
Следовательно, std::array<int, 3> arr2{1, 2, 3};
(примеры 0, 2, 6), строго говоря, некорректны. Насколько я знаю, последние версии clang++ и g++ уже допускают исключение скобок в T x { a };
.
В примере 6 std::array<int, 3>({1, 2, 3})
использует инициализацию копированием: инициализация для передачи аргументов также является инициализацией копированием. Однако ошибочное ограничение пропуска фигурных скобок, "В объявлении формы T x = { a };
", также запрещает исключение скобок для передачи аргументов, поскольку это не объявление и, конечно, не в такой форме.
По теме агрегатной инициализации:
Как указывает Йоханнес Шауб, в комментарии только гарантируется, что вы можете инициализировать std::array
со следующим синтаксисом [массив.обзор]/2:
array<T, N> a = { initializer-list };
Из этого можно сделать вывод, что, если исключение фигурных скобок разрешено в форме T x { a };
, что синтаксис
array<T, N> a { initializer-list };
правильно сформирован и имеет тот же смысл. Однако не гарантируется, что std::array
фактически содержит необработанный массив в качестве единственного элемента данных (см. также LWG 2310). Я думаю, что одним из примеров может быть частичная специализация std::array<T, 2>
, где есть два члена данных T m0
и T m1
. Следовательно, нельзя сделать вывод, что
array<T, N> a {{ initializer-list }};
хорошо сформирован. К сожалению, это приводит к тому, что не существует гарантированного способа инициализации временного исключения std::array
без скобок для T x { a };
, а также означает, что нечетные примеры (1, 3, 5, 7) не требуются для работы.
Все эти способы инициализации std::array
в конечном итоге приводят к агрегатной инициализации. Он определяется как копирование-инициализация элементов агрегата. Однако инициализация копированием с использованием списка инициализации в фигурных скобках может по-прежнему напрямую инициализировать составной элемент. Например:
struct foo { foo(int); foo(foo const&)=delete; };
std::array<foo, 2> arr0 = {1, 2}; // error: deleted copy-ctor
std::array<foo, 2> arr1 = {{1}, {2}}; // error/ill-formed, cannot initialize a
// possible member array from {1}
// (and too many initializers)
std::array<foo, 2> arr2 = {{{1}, {2}}}; // not guaranteed to work
Первый пытается инициализировать элементы массива из предложений инициализатора 1
и 2
соответственно. Эта копия-инициализация эквивалентна foo arr0_0 = 1;
, которая, в свою очередь, эквивалентна foo arr0_0 = foo(1);
, что является незаконным (удален копировал-ctor).
Второй содержит не список выражений, а список инициализаторов, поэтому он не соответствует требованиям [array.overview]/2. На практике std::array
содержит необработанный элемент данных массива, который будет инициализирован (только) из первого предложения инициализатора {1}
, тогда как второе предложение {2}
является недопустимым.
У третьего есть проблема, противоположная второму: он работает, если есть есть элемент данных массива, но это не гарантируется.
person
dyp
schedule
11.12.2013
-Wall -pedantic
. Сделайте то же самое для Clang, это очень помогает. Например, в arr 4 отсутствует вторая пара {}. - person usr1234567   schedule 11.12.2013arr0
иarr1
вообще работают; они называют движение-ctor? Если да, то они имеют другое значение, чем 2-5 (аналогично 6 и 7). - person dyp   schedule 11.12.2013arr0
, поэтому ваша нумерация добавила путаницы (во всяком случае, для меня) - person M.M   schedule 07.06.2015