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

Это правда, что goto перепрыгивает биты кода без вызова деструкторов и прочего?

например

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

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

не будет x быть утечкой?

1 ответ

Решение

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


не будет x быть утечкой?

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

Это миф, что goto это некая низкоуровневая конструкция, которая позволяет вам переопределить встроенные в C++ механизмы определения области действия. (Во всяком случае, это 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 для любой конкретной проблемы, но это означает, что она не так "зла", как обычный миф, заставляющий людей верить.

Другие вопросы по тегам