case 문에서 {} 사용. 왜? 줄이 있더라도 모든 줄이

문 에서 {및 사용의 요점은 무엇입니까 ? 일반적으로 명령문 에 몇 줄이 있더라도 모든 줄이 실행됩니다. 이것은 단지 구형 / 최신 컴파일러에 관한 규칙입니까, 아니면 그 뒤에 뭔가가 있습니까?}casecase

int a = 0;
switch (a) {
  case 0:{
    std::cout << "line1\n";
    std::cout << "line2\n";
    break;
  }
}

int a = 0;
switch (a) {
  case 0:
    std::cout << "line1\n";
    std::cout << "line2\n";
    break;
}



답변

{}새로운 블록 나타낸다 범위 .

다음과 같은 매우 인위적인 예를 고려하십시오.

switch (a)
{
    case 42:
        int x = GetSomeValue();
        return a * x;
    case 1337:
        int x = GetSomeOtherValue(); //ERROR
        return a * x;
}

x범위에 이미 정의되어 있기 때문에 컴파일러 오류가 발생 합니다.

이를 자체 하위 범위로 분리 x하면 switch 문 외부에서 선언 할 필요가 없습니다 .

switch (a)
{
    case 42: {
        int x = GetSomeValue();
        return a * x;
    }
    case 1337: {
        int x = GetSomeOtherValue(); //OK
        return a * x;
    }
}


답변

TL; DR

이니셜 라이저 또는 케이스 내에서 사소하지 않은 개체를 사용하여 변수를 선언 할 수있는 유일한 방법 은 루프 또는 if 문과 같은 자체 범위가있는 다른 제어 구조를 사용하여 블록 범위 를 도입하는 {}것 입니다.

피투성이 세부 사항

우리는 볼 수있는 경우가 바로되어 제표 표시라벨 와 함께 사용 고토 문 ( 이은으로 덮여 표준 초안 C ++ 6.1 레이블 문 ) 우리는 절에서 볼 수있는 6.73 많은 경우에 허용되지 않습니다 점프 선언을 통과하는 것이 , 초기화 포함 :

블록으로 전송할 수 있지만 초기화를 통해 선언을 우회하는 방식은 아닙니다. 자동 저장 기간이있는 변수가 범위 내에 있지 않은 지점에서 범위 내에있는 지점으로 87 을 점프하는 프로그램 은 변수에 스칼라 유형, 사소한 기본 생성자가있는 클래스 유형 및 사소한 소멸자가 없으면 형식이 잘못되었습니다. 이 유형 중 하나의 cv 규정 버전 또는 이전 유형 중 하나의 배열이며 이니셜 라이저없이 선언됩니다 (8.5).

이 예제를 제공합니다.

void f() {
 // ...
 goto lx; // ill-formed: jump into scope of a

 ly:
  X a = 1;
 // ...
 lx:
  goto ly; // OK, jump implies destructor
          // call for a followed by construction
          // again immediately following label ly
}

여기에는 몇 가지 미묘한 점이 있습니다. 초기화가없는 스칼라 선언건너 뛸 수 있습니다. 예를 들면 다음과 같습니다.

switch( n )
{
    int x ;
    //int x  = 10 ; 
    case 0:
      x = 0 ;
      break;
    case 1:
      x = 1 ;
      break;
    default:
      x = 100 ;
      break ;
}

완벽하게 유효합니다 ( 라이브 예제 ). 물론 각 경우에 동일한 변수를 선언하려면 각각 고유 한 범위가 필요하지만 switch 문 외부에서도 동일한 방식으로 작동 하므로 큰 놀라지 않아야합니다.

초기화를 넘어서 점프를 허용하지 않는 이유에 대해서는 약간 다른 문제를 다루지 만 결함 보고서 467자동 변수에 대한 합리적인 사례를 제공 합니다 .

[…] 자동 변수는 명시 적으로 초기화되지 않은 경우 트랩 표현을 포함하여 불확실한 ( “가비지”) 값을 가질 수 있습니다. […]

스위치 내에서 범위 를 여러 경우로 확장하는 경우를 살펴 보는 것이 더 흥미로울 것입니다 . 가장 유명한 예는 다음과 같은 Duff의 장치 일 것입니다 .

void send( int *to, const int *from, int  count)
{
        int n = (count + 7) / 8;
        switch(count % 8)
        {
            case 0: do {    *to = *from++;   // <- Scope start
            case 7:         *to = *from++;
            case 6:         *to = *from++;
            case 5:         *to = *from++;
            case 4:         *to = *from++;
            case 3:         *to = *from++;
            case 2:         *to = *from++;
            case 1:         *to = *from++;
                        } while(--n > 0);    // <- Scope end
        }
}


답변

결과 소멸자 (또는 범위 충돌)가있는 변수 선언을 case절 에 삽입 할 수있는 습관입니다 . 그것을 보는 또 다른 방법은 그들이 원하는 언어로 작성하는 것입니다. 모든 흐름 제어는 문장의 시퀀스가 ​​아니라 블록으로 구성됩니다.


답변

이것이 기본적인 컴파일러 제한인지 확인하면 무슨 일이 일어나는지 궁금해 할 것입니다.

int c;
c=1;

switch(c)
{
    case 1:
    //{
        int *i = new int;
        *i =1;
        cout<<*i;
        break;
    //}

    default : cout<<"def";
}

그러면 오류가 발생합니다.

error: jump to case label [-fpermissive]
error:   crosses initialization of int* i

이것은 다음을 수행하지 않습니다.

int c;
c=1;

switch(c)
{
    case 1:
    {
        int *i = new int;
        *i =1;
        cout<<*i;
        break;
    }

    default : cout<<"def";
}


답변

스위치에서 대괄호를 사용하는 것은 Rotem이 말한 것처럼 새로운 범위 블록을 나타냅니다.

그러나 읽을 때 명확하게 할 수도 있습니다. 조건부 중단이있을 수 있으므로 케이스가 중지되는 위치를 파악합니다.


답변

이유는 다음과 같습니다.

  1. 가독성, 범위가 지정된 섹션으로 각 사례를 시각적으로 향상시킵니다.
  2. 여러 스위치 케이스에 대해 동일한 이름으로 다른 변수를 선언합니다.
  3. 마이크로 최적화-케이스의 범위를 벗어나 자마자 파괴하려는 정말 값 비싼 리소스 할당 변수의 범위 또는 “GOTO”명령 사용에 대한 더 스파게티 시나리오.

답변