티스토리 뷰


함수의 초기화 과정에서 종종 goto문을 사용하곤 한다.

예를 들면 열 가지 정도의 변수에 메모리를 할당 해 주는데, 다섯번째쯤 되는 변수를 처리하는 과정에서 오류가 발생했다고 가정해보자.


그럼 앞에 메모리가 할당된 네 개의 변수는 어떻게 될까?

할당해놓고 해제해 준 적이 없으니 메모리 누수상태가 된다. (Memory Leak)


그래서 변수 처리중에 에러가 발생 하면, 바로 return을 해버리는게 아니라 goto문을 이용하여 error 처리부로 이동시켜 메모리 해제해주는 작업을 거치게 된다.

윈도우에서 제공하는 try-finally 와 유사하다고 보면된다.


goto문을 사용하는 간단한 예제는 다음과 같다.

int Initialize()
{
    // 이 예제에서는 CDialog라는 클래스가 있다고 가정한다.
    CDialog *dlgA;
    CDialog *dlgB;
    CDialog *dlgC;

    dlgA = new CDialog;
    if( dlgA->InitDialog() < 0 )    // Error 발생시,
    {
        goto _error;
    }

    dlgB = new CDialog;
    if( dlgB->InitDialog() < 0 )    // Error 발생시,
    {
        goto _error;
    }

    dlgC = new CDialog;
    if( dlgC->InitDialog() < 0 )    // Error 발생시,
    {
        goto _error;
    }

    // no error
    return 0;

_error:
    if( dlgA != NULL )
    {
        delete dlgA;
        dlgA = NULL;
    }
    if( dlgB != NULL )
    {
        delete dlgB;
        dlgB = NULL;
    }
    if( dlgC != NULL )
    {
        delete dlgC;
        dlgC = NULL;
    }

    return -1;
}



goto문에서 컴파일 에러가 나요

제목은 goto문 에러에 관한 내용인데, goto문을 설명하는데 너무 많은 시간과 지면을 할당했다.

암튼, 가끔 goto를 잘 쓰다가도 이런 컴파일 에러를 만날 수 있다.


jump to label _error [-fpermissve]

_error 자리에는 goto할 레이블의 이름이 들어간다.


왜 생길까?


C언어 시절 변수 선언을 생각 해 보자.

C언어 시절에는 모든 변수의 선언은 블럭의 최상단에 했어야 했다.

블럭이란 { } 로 감싸진 코드블럭을 말한다.


하지만 C++로 들어와서는 블럭의 최상단이 아닌 어디에서도 변수의 선언을 할 수 있게 되었다.


다음 코드 예제를 보도록 하자

int func()
{
    int a;    // c, c++ 모두 가능
    a = 3;

    int b = 2;    // c 오류, c++ 가능

    if( a > b )
    {
        int res;    // c, c++ 모두 가능
        res = a - b;
  
        int res2;    // c 오류, c++ 가능
        
        {
            int res3;  // c, c++ 모두 가능
        }

        for( int i = 0; i < b; i++)  // c 오류, c++ 가능
        {
            printf("%d\n", i);
        }
    }
    return 0;
}



이렇게 변수의 선언에 관한 C, C++문법의 차이를 열심히 설명하는 이유.

goto는 C Style로 변수 선언을 하면 에러가 나지 않는다.


즉, 최소한 goto 이하에 C++형식으로 변수가 선언된 흔적이 없어야 한다.



<goto 에러 형태>

int Initialize()
{
    CDialog *dlgA;
    CDialog *dlgB;

    digA = new Dialog;
    if( digA->InitDialog() < 0 )
    {
        goto _error;
    }

    // c++형식의 변수 선언을 했기 때문에 에러가 발생한다.
    bool bShown = digA->isShow();
    if( bShown == true )
    {
        goto _error;
    }

    if( digB->InitDialog() < 0 )
    {
        goto _error;
    }

    return 0;

_error:
    if( dlgA != NULL )
    {
        delete dlgA;
        dlgA = NULL;
    }
    if( dlgB != NULL )
    {
        delete dlgB;
        dlgB = NULL;
    }

    return -1;
}


<에러 우회 방법>

int Initialize()
{
    CDialog *dlgA;
    CDialog *dlgB;

    digA = new Dialog;
    if( digA->InitDialog() < 0 )
    {
        goto _error;
    }

    // c에서도 가능한 변수 선언 형태로 만들어주면 된다.
    // 단, 이 때 변수의 생명력(?)은 블럭 내부에 한정된다.
    {
        bool bShown = digA->isShow();
        if( bShown == true )
        {
            goto _error;
        }
    }

    if( digB->InitDialog() < 0 )
    {
        goto _error;
    }

    return 0;

_error:
    if( dlgA != NULL )
    {
        delete dlgA;
        dlgA = NULL;
    }
    if( dlgB != NULL )
    {
        delete dlgB;
        dlgB = NULL;
    }

    return -1;
}



사실 goto가 C언어용 문법이라서 에러가 나는건 아니다.

goto의 특성 자체가 코드의 위, 아래 영역을 자유롭게 넘나드는 형태인데, 넘나드는 그 사이 영역에 변수가 새로 할당되는 동작이 있거나 하면 문법상 오류가 날 수 있다.


goto문 이후 변수를 할당해주었고, goto된 레이블로 이동 후 해당 변수를 사용할 수 있을까? 없을까? 컴파일러는 과연 이 사실을 알 고 있을까?


그래서 컴파일러가 goto문 아래로 변수 선언을 못하게 막은것 아닐까?



C Style 변수 선언을 하면 절대 오류가 나지 않기 때문에, 알기 쉽게 그렇게 설명한 것 뿐이다. :)





저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

댓글
댓글쓰기 폼