Стандартная ссылка для int foo = foo - PullRequest
19 голосов
/ 31 мая 2011

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

Ответы [ 2 ]

26 голосов
/ 31 мая 2011

3.3.1 Пункт объявления [basic.scope.pdecl]

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

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

21 голосов
/ 31 мая 2011

Это

int main() {
  int foo = foo;
}

Объект foo существует после =, согласно [basic.scope.pdecl]:

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

Однако программа в целом не определена, поскольку вы используете (в RHS) неинициализированное значение:

int x = x; Здесь [..] x инициализируется своим собственным (неопределенным) значением.

И

Несмотря на то, что стандарт "подразумевает и неправильно определяет", и преобразование lvalue в rvalue выполняется для выражения RHS foo.

А ([conv.lval]):

lvalue (3.10) не функции, не массив типа T может быть преобразован в значение. Если T является неполным типом, программа, которая требует этого обращение плохо сформировано. Если Объект, на который ссылается lvalue, не является объектом типа T и не является объект типа, производного от T, или , если объект неинициализирован, программа что требует этого преобразования имеет неопределенное поведение.

При правильном уровне предупреждения вам сообщат об этом ; однако, программы, вызывающие неопределенное поведение, могут компилироваться. Они просто могут делать что угодно, когда вы их запускаете.


Или как насчет этого?

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 не используется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...