Подтвердить что ты не робот

Почему "int я = i;" законно?

Возможный дубликат:
int var = 1; void main() {int я = i; }

Следующий код может передавать компиляцию под g++ и Visual С++. Почему это законно? Это выглядит необоснованным и может вызвать скрытые ошибки.

int main() {
  int i = i;
}
4b9b3361

Ответ 1

EDIT: синтаксически законный, но приводит к поведению undefined, если вы используете x.

Это не, поскольку вы назначаете неинициализированную переменную другой (ну, той же) неинициализированной переменной. Просто потому, что он компилируется, это не значит, что это законно. Это допустимый синтаксис С++, да, но не законный.

Правая часть оператора присваивания должна быть полностью оценена во время назначения. В этом случае это i, которое не инициализировано.

Кредиты Стиву Джессопу, который выкопал цитату:

4.1/1, преобразование lvalue-to-r

[...], если объект не инициализирован, программа, которая требует этого преобразование имеет поведение undefined.

Ответ 2

Поводом для синтаксиса является то, что есть некоторые нечетные случаи, когда вы, возможно, захотите использовать переменную указателем или ссылкой в ​​своем собственном инициализаторе:

struct ThingManager {
    void *thing;
    ThingManager(void *thing) : thing(thing) {}
    void Speak() {
        if (thing == (void*)this) {
            std::cout << "I'm managing myself\n";
        } else {
            std::cout << "I'm managing " << thing << "\n";
        }
    }
};

ThingManager self_manager(&self_manager);
ThingManager other_manager(&self_manager);

Итак, С++ позволяет ссылаться на объект в его собственном выражении инициализатора (его имя находится в области). Затем, как и в С++, ваша проблема заключается в том, чтобы убедиться, что вы фактически не используете неинициализированное значение (ваш пример int i = i; использует неинициализированное значение).

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

Ответ 3

Вы можете позволить g++ предупредить вас об этом случае использования с -Winit-self (в сочетании с -Wuninitialized), и если вы рассматриваете предупреждения как ошибки, он должен удовлетворять вашему зуду.

Этот метод использования конструктора копирования для самоинициализации иногда используется для подавления конструктора/инициализатора по умолчанию глобального объекта по умолчанию. Это может потребоваться, если конструктор по умолчанию для глобального объекта только для 0 инициализирует объект, но объект был использован до того, как конструктор будет выполнен. В качестве возврата к C глобальные переменные 0 инициализируются при запуске программы, а затем среда выполнения С++ начинает выполнять глобальные конструкторы. В тех узких случаях, когда определенный конструктор, который выполнил бы, был бы только 0 из объекта, само инициализация не наносит вреда.

В общем случае самоинициализация конструктора копирования является плохой практикой, так как она обычно вызывает те же самые проблемы, что и использование неинициализированной переменной (то есть поведение undefined). В конкретном примере в вопросе OP i является локальным для main и поэтому неинициализирован. Результатом чтения неинициализированной переменной всегда является поведение undefined.

Ответ 4

Вы можете использовать любую ранее объявленную переменную в качестве инициализатора другой переменной.

В этом случае, как только компилятор разбирает int i, он добавляет это в таблицу символов, поэтому, когда он видит инициализатор = i, символ может быть разрешен из предыдущего объявления.

Это не ошибка, потому что компилятор может понять это, поскольку он может генерировать код, который однозначно выполняет именно то, что указывает исходный код, семь, если оно семантически подозревается. Философия C и С++ заключается в компиляции всего, что может быть скомпилировано синтаксически. Семантические ошибки обычно вызывают только предупреждения, и только тогда, если такие предупреждения включены.