Будет ли использовать переменные утечки goto?

Верно ли, что goto перескакивает биты кода без вызова деструкторов и вещей?

например.

void f() {
   int x = 0;
   goto lol;
}

int main() {
   f();
lol:
   return 0;
}

Не будет утечка x?

Ответ 1

Предупреждение: Этот ответ относится только к С++; правила в C очень разные.


Не будет утечка x?

Нет, абсолютно нет.

Миф о том, что goto - это низкоуровневая конструкция, которая позволяет вам переопределить встроенные механизмы С++. (Во всяком случае, он longjmp, который может быть склонен к этому.)

Рассмотрим следующие механики, которые мешают вам делать "плохие вещи" с метками (включая метки case).


1. Область ярлыков

Вы не можете перепрыгнуть через функции:

void f() {
   int x = 0;
   goto lol;
}

int main() {
   f();
lol:
   return 0;
}

// error: label 'lol' used but not defined

[n3290: 6.1/1]: [..] Объем метки - это функция, в которой кажется. [..]


2. Инициализация объекта

Вы не можете перейти через инициализацию объекта:

int main() {
   goto lol;
   int x = 0;
lol:
   return 0;
}

// error: jump to label ‘lol’
// error:   from here
// error:   crosses initialization of ‘int x’

Если вы отскакиваете от инициализации объекта, то объект предыдущего "экземпляра" уничтожается:

struct T {
   T() { cout << "*T"; }
  ~T() { cout << "~T"; }
};

int main() {
   int x = 0;

  lol:
   T t;
   if (x++ < 5)
     goto lol;
}

// Output: *T~T*T~T*T~T*T~T*T~T*T~T

[n3290: 6.6/2]: [..] Передача из цикла, из блока или обратно прошлая инициализированная переменная с автоматическим временем хранения включает уничтожение объектов с автоматическим временем хранения, которые находятся в объем в точке, переносимой из, но не в переданную точку к. [..]

Вы не можете перейти в область действия объекта, даже если он явно не инициализирован:

int main() {
   goto lol;
   {
      std::string x;
lol:
      x = "";
   }
}

// error: jump to label ‘lol’
// error:   from here
// error:   crosses initialization of ‘std::string x’

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

int main() {
   goto lol;
   {
      int x;
lol:
      x = 0;
   }
}

// OK

[n3290: 6.7/3]: Можно передать в блок, но не в способ, который обходит объявления с инициализацией. Программа, которая перескакивает из точки, где переменная с автоматической продолжительностью хранения не находится в пределах до точки, где она находится в сфере охвата, переменная имеет скалярный тип, тип класса с тривиальным значением по умолчанию конструктор и тривиальный деструктор, cv-квалифицированная версия одного из эти типы или массив одного из предыдущих типов и объявляется без инициализатора. [..]


3. Прыжки сохраняются по объему других объектов

Аналогично, объекты с автоматическим временем хранения не "просочились" , когда вы goto вышли из их области:

struct T {
   T() { cout << "*T"; }
  ~T() { cout << "~T"; }
};

int main() {
   {
      T t;
      goto lol;
   }

lol:
   return 0;
}

// *T~T

[n3290: 6.6/2]: При выходе из области действия (однако выполнено) объекты с автоматической продолжительностью хранения (3.7.3), которые были построены в этот объем разрушен в обратном порядке их строительства. [..]


Заключение

Вышеупомянутые механизмы гарантируют, что goto не позволит вам сломать язык.

Конечно, это автоматически не означает, что вы должны "использовать" goto для любой заданной проблемы, но это означает, что это не так, как "зло", поскольку общий миф заставляет людей поверить.