Инициализация массива С++
Возможный дубликат:
Как инициализировать массив в C
инициализация массива, ссылается на предыдущий элемент ok?
Интересно, насколько безопасно выполнить такую инициализацию в стандарте c/С++:
int a = 5;
int tab[] = { a , tab[0] + 1 , tab[1] };
Он успешно компилируется и выполняется с помощью gcc 4.5 и clang 2.9, но всегда ли это будет true?
Печать этой таблицы дает 5 6 6
. Его инициализируется в глобальном масштабе.
Как правило, это интересно в обоих, c и С++, но я хочу использовать его в С++:)
Ответы
Ответ 1
В стандарте C99 кажется, что порядок инициализации членов гарантирован:
§6.7.8/17: Каждый список инициализаторов, заключенных в фигурную скобку, имеет связанный текущий объект. Если не указано никаких обозначений, подобъекты текущего объекта инициализируются в соответствии с типом текущего объекта: элементы массива в возрастающем порядке подстроки, члены структуры в порядке объявления и первый именованный элемент союз. Напротив, обозначение заставляет следующий инициализатор начинать инициализацию подобъекта, описанного указателем. Инициализация затем продолжается в порядке, начиная со следующего подобъекта после того, как описана обозначением.
Но поскольку @Tomalak упоминает в комментарии, это не дает полной гарантии для операции, поскольку компилятор сначала оценит все аргументы, а затем применит результаты в предыдущем порядке. То есть предыдущая цитата не налагает порядок между инициализацией tab[0]
и оценкой выражения tab[0]+1
, который используется для инициализации tab[1]
(он налагает только порядок между инициализацией tab[0]
и tab[1]
)
Как и в стандарте С++, ни в текущем стандарте, ни в FDIS будущего С++ 0x, похоже, не существует конкретного предложения, определяющего порядок, в котором выполняется инициализация. Единственное упоминание о заказе происходит от
§8.5.1/2 Когда агрегат инициализируется, инициализатор может содержать предложение инициализатора, состоящее из списка разделенных запятыми списков инициализатор-предложений для членов агрегата, записанных при увеличении индекса или порядка членов.
Но это относится только к порядку записи записей в инициализаторе, а не к тому, как он фактически оценивается.
Ответ 2
С++ 03/С++ 11 answer
Нет, не будет.
В правой части =
, tab
существует 1 но — если он имеет автоматическую продолжительность хранения -— он еще не инициализирован, поэтому использование tab[0]
и tab[1]
использует неинициализированную переменную.
Если tab
находится в области пространства имен (и, следовательно, имеет статическую продолжительность хранения и инициализируется нулем), тогда это "безопасно", но использование tab[0]
не даст вам 5
.
Трудно предоставить стандартные ссылки для этого, кроме как сказать, что в 8.5 "Initializers"
нет ничего, что явно делает это возможным, а правила в других местах заполняют остальные.
1[n3290: 3.3.2/1]:
Точка объявления для имени сразу после его полного объявления (раздел 8) и перед его инициализатором (если есть) [..]
Ответ 3
int a =5;
int tab[] = { a , tab[0] + 1 , tab[1] };
Если эти переменные объявлены в области пространства имен, то они в порядке, так как при переменных пространства имен переменные нуль-инициализированы (из-за статической инициализации - читайте this для подробно).
Но если они объявлены в области функций, вторая строка вызывает поведение undefined, поскольку локальные переменные не статически инициализируются, это означает, что tab[0]
и tab[1]
не инициализированы, которые вы используете для инициализации массив. Чтение неинициализированных переменных вызывает поведение undefined.
Ответ 4
Итак, теперь я проверил пару тестов, касающихся вашей проблемы.
Все компиляции были выполнены с приведенным выше примером кода, используя следующую схему:
$(GCC) -o a.out test.c -Wall -Wextra -pedantic -std=$(STD)
Это дало следующие результаты:
для GCC = gcc
, стандарты -std=c89; -std=iso9899:1990; -std=iso9899:199409; -std=gnu89
привели к появлению предупреждения: initializer element is not computable at load time
и undefined поведение во время выполнения, что означает, что второе и третье значение массива были случайным мусором.
стандарты -std=c99; std=iso9899:1999; -std=gnu99
не дали этого предупреждения, но также показали поведение undefined во время выполнения.
для GCC = g++
, стандарты -std=c++98; -std=gnu++98; -std=c++0x
не выдали никаких предупреждений, и код работал так, как вы ожидали, в результате получился массив, содержащий значения {5, 6, 6}
.
Однако, поскольку большинство людей советовали, это может быть неразумно использовать это, поскольку ваш код может вести себя по-другому на других компиляторах или, возможно, даже на других версиях одного и того же компилятора, что обычно плохо:)
надеюсь, что это помогло.
Ответ 5
Да - он, вероятно, будет работать так, как вы ожидаете.
Нет - (вы не спрашивали, но) Не используйте его, он не делает логики, и это плохая практика.