int foo = foo;
компилируется. Какая часть стандарта С++ разрешает это?
Стандартная ссылка для int foo = foo
Ответы (2)
3.3.1 Точка объявления [basic.scope.pdecl]
Точка объявления имени находится сразу после его полного декларатора (пункт 8) и перед его инициализатором (если есть).
Поведение хорошо определено, если объявление находится в области файла. Если у вас есть объявление в области действия функции и если вы используете foo
позже [которое в этом случае будет инициализировано некоторым неопределенным значением], поведение будет неопределенным.
s/program has/program may have/
; s/should not/possibly should not/
.
- person Lightness Races in Orbit; 31.05.2011
foo
позже не имеет значения; сама инициализация вызывает UB! Разве это не так?
- person Lightness Races in Orbit; 31.05.2011
A
неинициализированным B
(и A
, и B
оказываются одним и тем же объектом).
- person Lightness Races in Orbit; 31.05.2011
Этот?
int main() {
int foo = foo;
}
Объект foo
действительно существует после =
согласно [basic.scope.pdecl]
:
Точка объявления имени находится сразу после его полного декларатора (пункт 8) и перед его инициализатором (если есть).
Однако программа в целом не определена, потому что вы используете (в RHS) неинициализированное значение:
int x = x;
Здесь [..]x
инициализируется собственным (неопределенным) значением.
И:
Несмотря на то, что стандарт «предполагает и неправильно определяет», an < em>преобразование lvalue-to-rvalue выполняется для выражения RHS foo
.
И ([conv.lval]
):
Lvalue (3.10) типа T, не являющегося функцией или массивом, может быть преобразовано в rvalue. Если T — неполный тип, программа, требующая такого преобразования, некорректна. Если объект, на который ссылается lvalue, не является объектом типа T и не является объектом типа, производного от T, или если объект не инициализирован, программа, которая требует этого преобразования, имеет неопределенное поведение. >
При правильном уровне предупреждений вам сообщат об этом; однако программы, вызывающие Undefined Behavior, могут компилироваться. Они просто могут делать что угодно, когда вы их запускаете.
Или как насчет этого?
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
, и вы все еще застряли с Неопределенным поведением. Глобальный foo
не используется.
foo
происходит в области пространства имен), ему нужно указать это, потому что это полностью меняет вопрос.
- person Lightness Races in Orbit; 31.05.2011
unsigned char
.
- person Johannes Schaub - litb; 31.05.2011
foo
преобразуется в значение r для использования в правой части полного оператора?
- person Lightness Races in Orbit; 31.05.2011
int x = x;
UB? и Изменился ли стандарт C++ в отношении использования неопределенных значений и неопределенного поведения в C++14? - person Shafik Yaghmour   schedule 22.09.2015