Будет ли использование goto утечки переменных? - PullRequest
91 голосов
/ 07 сентября 2011

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

например

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

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

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

1 Ответ

206 голосов
/ 07 сентября 2011

Предупреждение: Этот ответ относится только к 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 для решения любой конкретной проблемы, но означает , что это вовсе не так «зло», как обычный миф, заставляющий людей верить.

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