십자가 초기화의 징후는 무엇입니까?


84

다음 코드를 고려하십시오.

#include <iostream>
using namespace std;

int main()
{
    int x, y, i;
    cin >> x >> y >> i;
    switch(i) {
        case 1:
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
            break;
        case 2:
            r = x - y;
            cout << r;
            break;
    };
}

G ++는 crosses initialization of 'int r'. 내 질문은 다음과 같습니다.

  1. 뭐가 crosses initialization ?
  2. 왜 첫 번째 이니셜 라이저는 x + y 가 컴파일을 통과했지만 후자가 실패한 입니까?
  3. 소위 문제는 무엇입니까 crosses initialization?

의 범위를 지정하기 위해 대괄호를 사용해야한다는 것을 알고 r있지만, 예를 들어 다중 케이스 switch 문에서 비 POD를 정의 할 수없는 이유를 알고 싶습니다.


1
아래 답변을 감안할 때 포인트 3에 대한 내 이해는이 오류가 C ++의 과도한 제한이라는 것입니다. 레이블 뒤에 r을 사용하지 않으면 영향이 없습니다 (여기 예제에서 r을 사용하더라도 경우 2에서 제거 할 수 있으며 컴파일러에서 동일한 오류가 발생 함). 더 나은 증거는 C와 C11에서도 허용된다는 것입니다.
calandoa

답변:


95

버전도 int r = x + y;컴파일되지 않습니다.

문제는 r이니셜 라이저가 실행되지 않고 범위에 올 수 있다는 것입니다 . 이니셜 라이저를 완전히 제거하면 코드가 잘 컴파일됩니다 int r;.

할 수있는 가장 좋은 방법은 변수의 범위를 제한하는 것입니다. 그렇게하면 컴파일러와 독자 모두를 만족시킬 수 있습니다.

switch(i)
{
case 1:
    {
        int r = 1;
        cout << r;
    }
    break;
case 2:
    {
        int r = x - y;
        cout << r;
    }
    break;
};

표준에 따르면 (6.7 / 3) :

블록으로 전송할 수 있지만 초기화를 통해 선언을 우회하는 방식은 아닙니다. 자동 저장 기간이있는 지역 변수가 범위 내에 있지 않은 지점에서 범위 내에있는 지점으로 점프하는 프로그램은 변수가 POD 유형 (3.9)이고 이니셜 라이저 (8.5)없이 선언되지 않는 한 잘못된 형식입니다.


하지만 내 G ++는 int r = x + y.
Jichao

10
글쎄, 내 g ++는 그렇지 않습니다. 다시 확인하거나 컴파일러를 업그레이드하십시오.
avakar

감사합니다. 도움이되었습니다. 나는 C 컴파일러가 일부 코드 뒤에 선언이 오는 것을 허용하지 않는다고 생각합니다 . 분명히 C99는 그것을 허용합니다 ... stackoverflow.com/questions/7859424/…
m-ric

36

case범위를 지정하려면 괄호 안에 의 내용을 넣어야합니다. 그러면 그 안에 지역 변수를 선언 할 수 있습니다.

switch(i) {
    case 1:
        {
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
        }
        break;
    case 2:
        ...
        break;
};

3

블록으로 전송할 수 있지만 초기화를 통해 선언을 우회하는 방식은 아닙니다. 자동 저장 기간이있는 지역 변수가 범위 내에 있지 않은 지점에서 범위 내에있는 지점으로 점프하는 프로그램은 변수에 POD 유형이 있고 이니셜 라이저없이 선언되지 않는 한 형식이 잘못되었습니다.

[Example: Code:

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
}

--end example]

이 점에서 switch 문의 조건에서 case 레이블로의 전송은 점프로 간주됩니다.


1
Stack Overflow에 오신 것을 환영합니다. 인용에 대한 출처를 제공해야합니다. 이것은 C ++ 03 : 6.7 / 3입니다. 또한 내 답변에서 인용 한 것과 동일한 단락입니다.
avakar

0

성명 r전에 변수 를 홍보하는 것이 좋습니다 switch. case블록 전체에서 변수를 사용하려는 경우 (또는 동일한 변수 이름이지만 다른 용도) switch 문 앞에 정의합니다.

#include <iostream>
using namespace std;

int main()
{
    int x, y, i;
    cin >> x >> y >> i;
// Define the variable before the switch.
    int r;
    switch(i) {
        case 1:
            r = x + y
            cout << r;
            break;
        case 2:
            r = x - y;
            cout << r;
            break;
    };
}

이점 중 하나는 컴파일러가 각 블록 에서 로컬 할당 (일명 스택에 푸시) 을 수행 할 필요가 없다는 것 case입니다.

이 접근법의 단점 break은 변수가 이전 값을 가지기 때문에 케이스가 다른 케이스로 "떨어지는"경우입니다 (예 :를 사용하지 않음 ).


2
나는 그것을 다른 방법으로 할 것을 제안합니다. 컴파일러는 두 경우 모두 "로컬 할당"을 수행 할 필요가 없습니다 (실제로는 수행하지 않습니다).
avakar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.