Стандартная ссылка для int foo = foo

int foo = foo; компилируется. Какая часть стандарта С++ разрешает это?


person Rohan    schedule 31.05.2011    source источник


Ответы (2)


3.3.1 Точка объявления [basic.scope.pdecl]

Точка объявления имени находится сразу после его полного декларатора (пункт 8) и перед его инициализатором (если есть).

Поведение хорошо определено, если объявление находится в области файла. Если у вас есть объявление в области действия функции и если вы используете foo позже [которое в этом случае будет инициализировано некоторым неопределенным значением], поведение будет неопределенным.

person Prasoon Saurav    schedule 31.05.2011
comment
Я бы +1, но вы совершенно не упомянули, что программа OP имеет неопределенное поведение и не должна использоваться. - person Lightness Races in Orbit; 31.05.2011
comment
@Tomalak: код может иметь UB, но не обязательно. ОП, кажется, полностью осознает, что это не то, что действительно следует использовать, и ему любопытно чисто академическое понимание того, почему оно вообще компилируется. - person Jerry Coffin; 31.05.2011
comment
@Tomalak: Не обязательно UB. OP конкретно не упомянул, находится ли объявление в области файла или в области функции? - person Prasoon Saurav; 31.05.2011
comment
@Прасун: s/program has/program may have/; s/should not/possibly should not/. - person Lightness Races in Orbit; 31.05.2011
comment
Использование foo позже не имеет значения; сама инициализация вызывает UB! Разве это не так? - person Lightness Races in Orbit; 31.05.2011
comment
@Prasoon: Верно, и он использует его при инициализации. Он инициализирует A неинициализированным BA, и 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 не используется.

person Lightness Races in Orbit    schedule 31.05.2011
comment
OTOH, если он глобальный, поведение определено. - person Jerry Coffin; 31.05.2011
comment
@Jerry: в моей программе нет глобальных переменных. Если в программе OP есть глобальные переменные (или если его объявление foo происходит в области пространства имен), ему нужно указать это, потому что это полностью меняет вопрос. - person Lightness Races in Orbit; 31.05.2011
comment
@ Джерри: хорошо. Тогда я добавлю пункт и для этого случая. - person Lightness Races in Orbit; 31.05.2011
comment
@ Томалак: +1. Отличный ответ. - person Jerry Coffin; 31.05.2011
comment
@Jerry: Ну, это было не без помощи, не так ли? :) - person Lightness Races in Orbit; 31.05.2011
comment
@Tomalak: нет, но это жизнь. Одним из признаков хорошего программиста (или почти любого другого) является готовность и способность принять помощь... - person Jerry Coffin; 31.05.2011
comment
@Tomalak: я добавил +1 к последнему абзацу. :) - person Prasoon Saurav; 31.05.2011
comment
оба ответа очень хороши, но я принял ответ Прасуна Саурава, потому что он первым опубликовал правильную цитату из стандарта. - person Rohan; 31.05.2011
comment
@Tomalak: в стандарте сказано, что инициализация - UB? (местный случай). Это логично, но я не помню ничего конкретного. - person Matthieu M.; 31.05.2011
comment
Может быть, ваши примеры будут еще более полными, если вы покажете, что происходит с чем-то еще, кроме базовых типов, например со структурой? - person Klaim; 31.05.2011
comment
@Klaim: применяются те же правила. - person Lightness Races in Orbit; 31.05.2011
comment
@Matthieu: изо всех сил пытаюсь найти цитату. - person Lightness Races in Orbit; 31.05.2011
comment
tomalak, в пункте 4.1 преобразования lvalue-to-rvalue говорится, что это UB (IIRC, в настоящее время нет под рукой спецификации). Примечательно, что это также UB для unsigned char. - person Johannes Schaub - litb; 31.05.2011
comment
@litb: Да, это говорит об этом; а есть ли здесь такое преобразование? - person Lightness Races in Orbit; 31.05.2011
comment
@Tomalak да, это говорит об этом :) - person Johannes Schaub - litb; 31.05.2011
comment
@litb: выражение foo преобразуется в значение r для использования в правой части полного оператора? - person Lightness Races in Orbit; 31.05.2011
comment
@Tomalak, @Johannes: Спасибо за цитату, я не подумал проверить правила конвертации! - person Matthieu M.; 01.06.2011