goto
소멸자와 사물을 호출하지 않고 코드 비트를 건너 뛰는 것이 사실 입니까?
예 :
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
x
유출 되지 않습니까?
답변
경고 : 이 답변은 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
주어진 문제 만은 않습니다 이 거의 믿을 수있는 일반적인 신화의 리드 사람들로 “악”으로하지 않습니다 것을 의미한다.