Почему деструктор вызывается при переходе назад через goto
Возможный дубликат:
Будет использоватьgoto
переменные утечки?
В следующем примере, когда goto
призван идти "назад", деструктор A
называется. Почему это так? объект a
не выходит за рамки своего, не так ли? Стандарт говорит что-нибудь об этом поведении относительно goto
?
void f()
{
start:
A a;
goto start;
}
4 ответа
6.6 Операторы переходов [stmt.jump]
Параграф 2:
При выходе из области (хотя и выполненной) объекты с автоматической продолжительностью хранения (3.7.3), которые были созданы в этой области, уничтожаются в порядке, обратном их построению. [Примечание: временные данные см. В 12.2. - конец примечания] Передача из цикла, из блока или обратно после инициализированной переменной с автоматической продолжительностью хранения включает в себя уничтожение объектов с автоматической продолжительностью хранения, которые находятся в области действия в точке, перенесенной из, но не в точке, переданной в, (См. 6.7 для переводов в блоки). [Примечание: Тем не менее, программа может быть остановлена (например, путем вызова std::exit() или std::abort() (18.5)) без уничтожения объектов класса с автоматическим хранением. - конец примечания]
Я думаю, что важная часть:
или обратно после инициализированной переменной с автоматическим сроком хранения включает в себя уничтожение
Время жизни объекта a
начинается с его объявления и продолжается до конца блока, содержащего его.
Это означает, что при переходе к предыдущему объявлению вы переходите к ситуациям стекового фрейма, где локальный элемент не существует, поэтому он должен быть уничтожен.
point of declaration
для имени сразу после его полного декларатора (пункт 8) и до его инициализатора (если есть), [...] (§ 3.3.2)Имя, объявленное в блоке (6.3), является локальным для этого блока; у этого есть область блока. Его потенциальная область действия начинается в точке объявления (3.3.2) и заканчивается в конце его блока. Переменная, объявленная в области видимости блока, является локальной переменной. (П. 3.3.3)
Вот соответствующая цитата из стандарта. Это даже включает пример, который почти идентичен вашему:
C++ 11 6.7 Заявление декларации [stmt.dcl]
2 Переменные с автоматической продолжительностью хранения (3.7.3) инициализируются каждый раз, когда выполняется их объявление-оператор. Переменные с автоматической продолжительностью хранения, объявленные в блоке, уничтожаются при выходе из блока (6.6).
3 Можно передавать в блок, но не так, чтобы обойти объявления с инициализацией. Программа, которая переходит из точки, в которой переменная с автоматическим хранением находится вне области действия, в точку, в которой она находится в области видимости, является плохо сформированной, если переменная не имеет скалярного типа, типа класса с тривиальным конструктором по умолчанию и тривиальным деструктором, cv-квалифицированная версия одного из этих типов или массив одного из предыдущих типов и объявляется без инициализатора (8.5). [ Пример:
void f() {
// ...
goto lx; // ill-formed: jump into scope of a
// ...
ly:
X a = 1;
// ...
lx:
goto ly; // OK, jump implies destructor
// call for a followed by construction
// again immediately following label ly
}
- конец примера]
Как объяснено в примере, goto
подразумевает разрушение. Декларация-заявление (A a;
в вашем коде) означает, что конструктор повторяется после каждого перехода.
Проще говоря... start:
является меткой и объявляет [другую область]
Если предположить, start
как есть <0x00003000>
А будет в <0x00003000> + some_offset
сказать <0x00003004>
,
goto start
попросит ПК (программный счетчик) перейти по адресу запуска, который происходит до объявления A - вне его области действия - следовательно, "уничтожить" a
"вызывает деструктор.