int foo = foo;
компилируется.
Какая часть стандарта С++ позволяет это?
Стандартная ссылка для int foo = foo
Ответ 1
3.3.1 Точка декларации [basic.scope.pdecl]
Точка объявления для имени сразу после его полного объявления (раздел 8) и перед его инициализатором (если есть),
Поведение хорошо определено, если декларация находится в области файлов. Если у вас есть объявление в области функций, и если вы используете foo
позже [, который будет инициализирован некоторым неопределенным значением в этом случае], это будет undefined.
Ответ 2
Это?
int main() {
int foo = foo;
}
Объект foo
существует после =
, согласно [basic.scope.pdecl]
:
Точка объявления для имени сразу после его полного объявления (раздел 8) и перед его инициализатором (если есть).
Однако программа в целом undefined, потому что вы используете (на RHS) неинициализированное значение:
int x = x;
Здесь [..]x
инициализируется собственным (неопределенным) значением.
и
Несмотря на то, что стандартное значение "выводится и плохо указано", преобразование lvalue-to-rvalue выполняется в выражении RHS foo
.
И ([conv.lval]
):
Значение (3.10) нефункции, тип без массива T может быть преобразован в rvalue. Если T - неполный тип, программа, которая требует этого преобразование плохо сформировано. Если объект, к которому относится значение lvalue не является объектом типа T и не является объект типа, полученного из T, или , если объект неинициализирован, программа что требует такого преобразования undefined.
С соответствующими уровнями предупреждения вам расскажут об этом; однако программам, вызывающим undefined Поведение, разрешается компилировать. Они просто могут что-то сделать, когда вы их запускаете.
Или, как насчет этого?
int foo = foo;
int main() {}
Обратите внимание, что foo
является "глобальным". Они инициализируются нулем в качестве первого шага в соответствии с [basic.start.init]
:
Объекты со статической продолжительностью хранения (3.7.1) должны быть инициализированы нулями (8.5) , прежде чем произойдет любая другая инициализация.
Итак, вы получите int foo
со значением 0; он действителен, в этот момент, согласно [basic.scope.pdecl]
выше, и согласно [stmt.decl]
:
Нулевая инициализация (8.5) всех локальные объекты со статическим хранилищем продолжительность (3.7.1) выполняется до любая другая инициализация имеет место. [..]
Затем вы инициализируете его значением foo
(сам), т.е. 0.
Это хорошо определено... если немного загадочно.
В интересах тщательности, здесь третий и последний случай:
int foo = 42;
int main() {
int foo = foo;
}
К сожалению, это то же самое, что и в первом случае. Поскольку локальный foo
уже объявлен и в области к моменту инициализации оценивается, инициализатор использует локальный foo
, и вы все еще придерживаетесь поведения undefined. Глобальный foo
не используется.