Это работает:
int arr[10] = {};
Все элементы arr
инициализируются значением в ноль.
Почему это не работает:
std::array<int, 10> arr({});
Я получаю следующее предупреждение от g ++ (версия 4.8.2):
предупреждение: отсутствует инициализатор для члена ‘std :: array<int, 10ul> :: _ M_elems ’
Есть две проблемы, одна из которых касается стиля и предупреждения.
Хотя это может быть неочевидно, агрегатная инициализация происходит на временном объекте, который затем используется в качестве аргумента для конструктора копирования. Более идиоматично делать эту инициализацию следующим образом:
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
превратить предупреждения в ошибки.
Во-первых, вы Можно использовать ({})
инициализатор с 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
версия = {}
синтаксис?
Достаточно людей отметили это как «проблему» при компиляции с -Werror
Я думаю, что стоит упомянуть, что проблема исчезнет, если вы просто удвоитесь:
std::array<int, 10> arr{{}};
Не выдает никаких предупреждений для меня на gcc 4.9.2.
Чтобы добавить, почему это решает это: я понимаю, что std :: array на самом деле является классом с массивом C в качестве единственного члена. Поэтому двойные скобки имеют смысл: внешние скобки указывают, что вы инициализируете класс, а затем внутренние скобки по умолчанию инициализируют один-единственный член класса.
Поскольку возможна двусмысленность, когда в классе есть только одна переменная, разумно использовать только одну пару {}, но здесь gcc слишком педантичен и предупреждает.