goto 누출 변수를 사용합니까?


94

goto소멸자와 사물을 호출하지 않고 코드 비트를 건너 뛰는 것이 사실 입니까?

예 :

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

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

x유출 되지 않습니까?


관련 : stackoverflow.com/questions/1258201/… (하지만 처음부터 깨끗하게하고 싶었습니다!)
궤도의 Lightness Races

15
무슨 "Won't x be leaked"뜻이야? 의 유형은 x내장 데이터 유형입니다. 더 나은 예를 선택하지 않으시겠습니까?
Nawaz 2011 년

2
@Nawaz : 예제는 완벽합니다. 내가 누군가에게에 대해 이야기 할 때마다 goto그들은 자동 저장 기간 변수조차 어떻게 든 "누수"되었다고 생각합니다. 당신과 내가 달리 알고 있다는 것은 완전히 요점이 아닙니다.
궤도의 가벼운 경주

1
@David : 변수에 사소하지 않은 소멸자가있을 때이 질문이 훨씬 더 의미가 있다는 데 동의합니다 ... 그리고 Tomalak의 답변을 살펴보고 그러한 예를 찾았습니다. 또한는 int누출 할 수 없지만 누출 될 수 있습니다 . 예를 들어 : void f(void) { new int(5); }누수 int.
Ben Voigt 2011 년

질문을 "주어진 예제에서 스택 및 기타 함수에서 반환 기능을 지우지 않고 코드 실행 경로가 f ()에서 main ()으로 전송됩니까? 소멸자가 필요한 경우 C에서도 같은가요? " 둘 다 질문의 의도를 유지하면서 가능한 오해를 피할 수 있을까요?
Jack V.

답변:


210

경고 : 이 답변은 C ++ 에만 해당됩니다 . 규칙은 C에서 상당히 다릅니다.


x유출 되지 않습니까?

아니, 절대 아닙니다.

gotoC ++의 기본 제공 범위 지정 메커니즘을 재정의 할 수있는 저수준 구조라는 신화입니다 . (무엇이든간에 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주어진 문제 만은 않습니다 이 거의 믿을 수있는 일반적인 신화의 리드 사람들로 "악"으로하지 않습니다 것을 의미한다.


8
C가 이러한 모든 위험한 일이 발생하는 것을 막지는 못한다는 것을 알 수 있습니다.
Daniel

13
@Daniel : 질문과 답변은 C ++에 관한 것입니다. 아마도 우리는 C와 C ++가 동일하다는 신화를 없애는 또 다른 FAQ를 가질 수 있습니다.)
Lightness Races in Orbit

3
@Tomalak : 나는 우리가 여기서 동의하지 않는다고 생각하지 않습니다. SO에 주어진 많은 답변은 어딘가에 명시 적으로 문서화되어 있습니다. 저는 C 프로그래머가이 답변을보고 C ++에서 작동한다면 C에서도 유사하게 작동해야한다고 가정하고 싶을 수도 있다는 점을 지적했습니다.
Daniel

2
또한 이러한 모든 초기화 작업이 케이스 레이블에 대해 동일하다는 점을 추가 할 수 있습니다.
PlasmaHH

12
와, 방금 C ++의 의미가 goto에 대해 깨 졌다고 생각했지만 놀랍게도 정상입니다! 좋은 대답입니다.
Joseph Garvin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.