Почему я могу инициализировать обычный массив из {}, но не std :: array

Это работает:

int arr[10] = {};

Все элементы arr инициализируются значением в ноль.

Почему это не работает:

std::array<int, 10> arr({});

Я получаю следующее предупреждение от g ++ (версия 4.8.2):

предупреждение: отсутствует инициализатор для члена ‘std :: array<int, 10ul> :: _ M_elems ’

10

Решение

Есть две проблемы, одна из которых касается стиля и предупреждения.

Хотя это может быть неочевидно, агрегатная инициализация происходит на временном объекте, который затем используется в качестве аргумента для конструктора копирования. Более идиоматично делать эту инициализацию следующим образом:

std::array<int, 10> arr = {};

Хотя это все еще оставляет предупреждение.

Предупреждение покрыто Отчет об ошибке gcc: — Запрос на расслабление инициализации поля Wmissing и один из комментариев говорит:

[…] Конечно, синтаксис C ++: MyType x = {}; должны быть поддержаны,
как видно здесь:

http://en.cppreference.com/w/cpp/language/aggregate_initialization

где, например:

struct S {
int a;
float b;
std::string str;
};

S s = {}; // identical to S s = {0, 0.0, std::string};

Это не должно предупреждать по причинам, изложенным в предыдущих комментариях.

и последующий комментарий говорит:

Мое утверждение о нулевой инициализации было неточным (спасибо), но
общая точка зрения остается в силе: в C вы должны написать ‘= {0}’, так как
инициализатор пустых скобок не поддерживается языком (вы получаете
предупреждение с -педантиком); в C ++ вы можете написать ‘= {}’ или ‘T foo =
T (); ‘, но вам не нужно писать’ = {0} ‘специально.

Последние версии gcc не выдают это предупреждение для этого случая, увидеть его вживую работая с gcc 5.1.

Мы также можем увидеть эту тему в списках разработчиков Clang в thead: -Wmissing поля инициализаторов.

Для справки проект стандартного раздела C ++ 11 8.5.1 [Dcl.init.aggr] говорит:

Если в списке меньше инициализаторов, чем
члены в совокупности, то каждый член не инициализирован явно
должен быть инициализирован из пустого списка инициализатора (8.5.4). [
Пример:

struct S { int a; const char* b; int c; };
S ss = { 1, "asdf" };

инициализирует ss.a с 1, ss.b с «asdf» и ss.c со значением
выражение вида int (), то есть 0. — конец примера]

Так как это действительно C ++, хотя, как было отмечено, используя {} не действителен C99. Можно утверждать, что это всего лишь предупреждение, но это похоже на идиоматический C ++, использующий {} для агрегатной инициализации и проблематично, если мы используем -Werror превратить предупреждения в ошибки.

12

Другие решения

Во-первых, вы Можно использовать ({}) инициализатор с std::array объект, но семантически это означает прямую инициализацию с использованием конструктора копирования из временного инициализированного значения std::array объект, то есть он эквивалентен

std::array<int, 10> arr(std::array<int, 10>{});

И это на самом деле должно компилироваться.

Во-вторых, вам не нужно идти ({}) путь, когда вы можете просто сделать

std::array<int, 10> arr = {};

или же

std::array<int, 10> arr{};

Первый из двух наиболее синтаксически похож на ваш int arr[10] = {};Это заставляет меня задуматься, почему ты не попробовал это сначала. Почему вы решили использовать ({}) вместо = {} когда вы построили std::array версия = {} синтаксис?

5

Достаточно людей отметили это как «проблему» при компиляции с -Werror Я думаю, что стоит упомянуть, что проблема исчезнет, ​​если вы просто удвоитесь:

std::array<int, 10> arr{{}};

Не выдает никаких предупреждений для меня на gcc 4.9.2.

Чтобы добавить, почему это решает это: я понимаю, что std :: array на самом деле является классом с массивом C в качестве единственного члена. Поэтому двойные скобки имеют смысл: внешние скобки указывают, что вы инициализируете класс, а затем внутренние скобки по умолчанию инициализируют один-единственный член класса.

Поскольку возможна двусмысленность, когда в классе есть только одна переменная, разумно использовать только одну пару {}, но здесь gcc слишком педантичен и предупреждает.

2
По вопросам рекламы [email protected]