Метки заставляют объекты создаваться и разрушаться?
Почему эта программа выводит aAaA, а не aaAA или aA?
#include <iostream>
struct A {
A() { std::cout << "a"; }
~A() { std::cout << "A"; }
};
int i;
int main() {
a:A a;
if (i-->=0) goto a;
}
Ответы (3 шт):
А что не так?
Зашли. Создался объект. Проверились - да, i>=0, пошли к метке a. Объект выходит из области видимости и уничтожается.
Создается новый. Проверка - i<0 - все, идем дальше. Окончание программы, объект выходит из области видимости, уничтожается...
aAaA
Что не так? :)
Ну да, это то же самое, что написать:
do {
A a;
} while (i-- >= 0);
объект локальный, и он каждый раз создается и уничтожается
Добавим побольше точек вывода: https://ideone.com/C97AxT
#include <iostream>
using namespace std;
struct A
{
A() { cout << '+'; }
~A() { cout << '-'; }
};
int i;
int main()
{
cout << '^';
a:
cout << '0';
A a;
cout << '1';
if (i-- >= 0) {
cout << 'g';
goto a;
}
cout << '$';
}
Получается:
^0+1g-0+1$-
Видим два создания объекта и 2 уничтожения. Уничтожения происходят в конце жизни объекта, который наступает сразу после goto и сразу после конца функции. Таким образом само по себе наличие goto не влияет на область жизни, влияет именно его исполнение.
Почему так делается, я точно не знаю, но у меня есть предположение. Компилятор обязан обеспечить корректность вызова конструкторов и деструкторов, а переход через goto в данном случае завершает блок - никакой другой возможности уничтожить переменную не будет. Теоретически, можно было бы пытаться уничтожить её после g0, но между g и 0 обратиться к ней затруднительно. Во-первых, очевидно, что в пару к goto поставить деструктор проще, во-вторых в принципе это выглядит логичнее - как конец блока по аналогии с break или continue, а не как неизвестное место перед вызовом конструктора (а если ещё один goto и он вообще не вызовется?). Два значения одна переменная хранить не может.
Почему я акцентировал влияние на данном случае? Потому что компилятор понимает, что переход делается выше переменной. Если мы немного переставим строки и поднимем объявление переменной выше метки (https://ideone.com/ZLK6xb), то она не будет уничтожена:
^+01g01$-