예외 처리 팁 ( try ~ catch )
예외처리는 JAVA에서 처음 본 개념 이었다.(수정일 : 2007년 07월 01일)
그 분기로 점프하는건줄 알았는데 그거랑은 약간
달른 것이었다.
VB에서 볼 수 있는 ON ERROR GOTO처럼 에러가 나면
그 분기로 점프하는 것 인줄 알았는데, 그것과는 약간
다른 것이었다.(수정일 : 2007년 07월 01일)
같았고 오히려 ON ERROR GOTO보다 더 유용할 뜻 보인다.
(이전까지는 예외 처리가(try ~ catch가) 왜 있는지 몰랐다.)
조금만 더 생각해 보면 ON ERROR GOTO처럼 구현할 수 있을 것
같고 오히려 ON ERROR GOTO보다 더 유용할 듯 보인다.
(이전까지는 예외 처리인 (try ~ catch가) 왜 있는지 몰랐다.)
(수정일 : 2007년 07월 01일)
우선 내가 그동안은 try ~ catch를 등한시 여기다가 갑자기 관심을 갖게 된 것은
필요한 곳을 찾았기 때문이다.
그동안 코딩을 하면서 메모리 누수가 발생해도 어쩌다가 발생한거니
그리 크게 생각 안하고 대충 프로그램 다시 실행하여서 오류 안나는 동작만
하곤 했다.
하지만 try ~ catch를 다시 곰곰히 보니 어떻게 써야 할지 알았다.
[CODE type=cpp]char *pMem = (char *)malloc( 40 * sizeof( char ) );
if( pMem == NULL )
return FALSE;
while( 1 )
{
이런 저런 수행 문;
if( 에러 발생? )
{
if( pMem != NULL )
{
free( pMem );
pMem = NULL;
return FALSE;
}
}
}
if( pMem != NULL )
{
free( pMem );
pMem = NULL;
return TRUE;
}[/CODE]
if( pMem == NULL )
return FALSE;
while( 1 )
{
이런 저런 수행 문;
if( 에러 발생? )
{
if( pMem != NULL )
{
free( pMem );
pMem = NULL;
return FALSE;
}
}
}
if( pMem != NULL )
{
free( pMem );
pMem = NULL;
return TRUE;
}[/CODE]
여기서 처럼 난 항상 if문으로 에러 났을 경우 상황을 대처하곤 했다.
그래도 별 문제는 없었다.
하지만 오늘 발생하고야 말았다. 그것은 if문으로 에러 처리를 할 경우
코드가 너무 방대해지고, 같은 코드를 계속 넣어야 한다는 것이다.
[CODE type=cpp] if( pMem != NULL )
{
free( pMem );
pMem = NULL;
return FALSE;
}[/CODE]
{
free( pMem );
pMem = NULL;
return FALSE;
}[/CODE]
프로그램 수행중 에러가 나고 함수에서 빠져 나갈때 잡았던 메모리를 풀어줘야 한다.
그런데 이 구문을 수행하지 않고 리턴을 하게 된다면, 처음에야 오류가 나지 않지만
나중에 가서 알 수 없게 오류가 발생하게 된다.
물론 코딩할때 신중하게 저 코드를 다 써준다면 괜찮지만, 문제는 귀차니즘과 유지보수에
있다.
저런 코드를 매번 삽입하는 번거로움은 둘째 치고, 만약 메모리 변수를 하나 더 선언하게
된다면?
[CODE type=cpp]char *pTmp = (char *)malloc( 10 * sizeof( char ) );[/CODE]
이 변수를 추가 한다면 return FALSE, return TRUE; 구문 전에 free(pTmp) 라는 구문을
더 추가 해줘야한다. 한 줄 뿐이겠지만, 나중에 코드가 복잡해진다면 일일이 찾아
넣기란 매우 번거롭고 헷갈릴 것이다.
이를 try ~ catch문으로 쉽게 해결 할 수 있게 되었다.
[ < try ~ catch문의 간단한 이론 부분 보기 > - 클릭 | < try ~ catch문의 간단한 이론 부분 보기 접기 > - 클릭 ]
try : 정상적인 코드 실행 부분
catch : 오류가 발생되면 호출되는 부분이다. throw exception을 잡아낸다.
finally : 오류가 발생하든, 하지 않든 반드시 수행하는 코드(C++에는 없는 기능, 2007.12.27 수정)
throw : exception handler를 초기화 한다
terminate() 와 unexpected()도 있는데 이것은 예외를 처리할 예외 처리기(catch)가
없을 때 호출된다. 하지만 이것을 실행하게 되면 abnormal program termination 디버그 에러가
발생하고 프로그램이 종료 된다.
try : 정상적인 코드 실행 부분
catch : 오류가 발생되면 호출되는 부분이다. throw exception을 잡아낸다.
throw : exception handler를 초기화 한다
terminate() 와 unexpected()도 있는데 이것은 예외를 처리할 예외 처리기(catch)가
없을 때 호출된다. 하지만 이것을 실행하게 되면 abnormal program termination 디버그 에러가
발생하고 프로그램이 종료 된다.
중요한것은 try, catch, throw
우선 위의 예제부터 try ~ catch로 바꾸어 보자
[CODE type=cpp]char *pMem = (char *)malloc( 40 * sizeof( char ) );
BOOL bResult = TRUE;
try
{
if( pMem == NULL )
throw "메모리할당 에러";
while( 1 )
{
이런 저런 수행 문;
if( 에러 발생? )
{
throw "기타 에러 발생";
}
}
}
catch( char *pE )
{
printf( "에러 발생\r\n %s", pE );
bResult = FALSE;
}
[/CODE]finally
{
[CODE type=cpp] if( pMem != NULL )
{
free( pMem );
pMem = NULL;
}
[/CODE]}
[CODE type=cpp]return bResult;[/CODE]
BOOL bResult = TRUE;
try
{
if( pMem == NULL )
throw "메모리할당 에러";
while( 1 )
{
이런 저런 수행 문;
if( 에러 발생? )
{
throw "기타 에러 발생";
}
}
}
catch( char *pE )
{
printf( "에러 발생\r\n %s", pE );
bResult = FALSE;
}
[/CODE]
{
[CODE type=cpp] if( pMem != NULL )
{
free( pMem );
pMem = NULL;
}
[/CODE]
[CODE type=cpp]return bResult;[/CODE]
이렇게 변할 것이다.
길이 상으론 오히려 더 복잡해 보인다.
하지만 프로젝트가 커질 수록 오히려 이런 방식이 유지보수하고, 오류 처리에 더 간단할 것이다.
그리고 try ~ catch에 관한 또 다른 예제문도 밑에 있다.
그냥 지나치기엔 안깝고도 자세한 설명이기에 그대로 긁어옴
(출처는 맨 밑에 표기 해뒀습니다)
[ <좀더 자세한 예제 보기> | <자세한 예제 접기> ]
try // 기본 코드
{
throw exception // catch로 예외처리 발생
}
catch (type exception) // 예외처리가 발생됨
{
// 예외 처리 구문
}
기본구조가 이런 형식을 가지고 있습니다.
이 형식을 가지고 한번 예제를 만들어 봅시다
try
{
printf("안녕 catch야!\r\n");
throw "왜불러 try!";
}
catch(char *s)
{
printf("%s\r\n", s);
}
- 실행 결과 -
안녕 catch야!
왜불러 try!
자 실행이 되면 바로 try안으로 진입
=> 그후 바로 throw 키워드가 나옵니다. 이 키워드는 exception을 발생시키는 겁니다.
뜻은 던진다라는 뜻인데 한마디로 예외처리를 던져버린다는 뜻이죠. 해석하면
예외처리를 catch로 던져버린다고 생각하시면 됩니다.
예외처리를 발생시키는 거죠 예외처리가 발생되면 바로 catch문으로 가게 되는거구요
사용법이 throw [exception] 였죠? 그럼 앞에 "왜불러 try!"라는 스트링으로 예외처리를
발생시켰습니다. 이렇게 catch에서는 char*형으로 예외처리 값을 받게 됩니다.
아주 간단하게 끝났습니다. 그렇죠
그럼 또다른 예제를 봅시다
try
{
throw 1; 또는 throw "안녕";
}
catch(char *s)
{
printf("[%s]char*형으로 예외처리가 들어왔군!\r\n", s);
}
catch(int s)
{
printf("[%d]int형으로 예외처리가 들어왔군!\r\n", s);
}
자 결과는 throw 1을 사용할경우 정수형이니깐 catch할때 정수형에 맞춰서
int형으로 예외처리가 들어왔군!''라고 결과를 출력하게 됩니다.
throw "안녕" 일경우에는 스트링으로 예외처리를 발생시켰으므로 catch의 char*형을 찾아가
char*형으로 예외처리가 들어왔군!''라고 결과를 출력하게 됩니다.
아주 간단하죠 throw의 exception type이 catch의 인자와 유형이 똑같아야 catch에서 예외처리를
받아 들이게 됩니다? 아셨죠?
만약 다음과 같이 인자의 형이 틀리게 되면 어떡해 될까요?
try
{
throw 1;
}
catch(char *s)
{
printf("[%s]char*형으로 예외처리가 들어왔군!\r\n", s);
}
아까 위해서 말한 시스템 함수인
terminate()가 호출되어 abnormal program termination 에러가 발생하여 종료 됩니다.
throw의 예외처리 값이 1이 들어갔는데 catch에는 char*형뿐이 없으니
예외처리를 찾을 수 없게 되어 결국은 디폴트값으로 시스템 제공 함수인 terminate()이 호출되어
프로그램이 종료됩니다.
아셨죠?
또는 바깥에 함수를 만들어서 호출하여 예외처리를 발생 시킬수 있습니다.
void f() throw()
{
throw 1;
}
void main()
{
try
{
f(); //함수를 호출하여 예외처리를 발생시킵니다
}
catch(int s)
{
printf("[%d]int형으로 예외처리가 들어왔군!\r\n", s);
}
}
또다른 예제를 봅시다
try
{
throw "방가워";
}
catch(char*)
{
printf("하이");
}
자 이방식은 char*에 유형만 주고 아까처럼 char *s변수로 받는것은 넣지 않았죠
이렇게 유형으로만 예외처리를 발생시킬 수도 있습니다.
그리고 throw에 클래스를 넣어 예외처리를 발생 할 수 있습니다.
그것도 방식은 똑같습니다. 한번 직접 코딩해보시기 바랍니다.
이상 간단한 예외처리 팁이였습니다. 그럼 수고하세요!
try // 기본 코드
{
throw exception // catch로 예외처리 발생
}
catch (type exception) // 예외처리가 발생됨
{
// 예외 처리 구문
}
기본구조가 이런 형식을 가지고 있습니다.
이 형식을 가지고 한번 예제를 만들어 봅시다
try
{
printf("안녕 catch야!\r\n");
throw "왜불러 try!";
}
catch(char *s)
{
printf("%s\r\n", s);
}
- 실행 결과 -
안녕 catch야!
왜불러 try!
자 실행이 되면 바로 try안으로 진입
=> 그후 바로 throw 키워드가 나옵니다. 이 키워드는 exception을 발생시키는 겁니다.
뜻은 던진다라는 뜻인데 한마디로 예외처리를 던져버린다는 뜻이죠. 해석하면
예외처리를 catch로 던져버린다고 생각하시면 됩니다.
예외처리를 발생시키는 거죠 예외처리가 발생되면 바로 catch문으로 가게 되는거구요
사용법이 throw [exception] 였죠? 그럼 앞에 "왜불러 try!"라는 스트링으로 예외처리를
발생시켰습니다. 이렇게 catch에서는 char*형으로 예외처리 값을 받게 됩니다.
아주 간단하게 끝났습니다. 그렇죠
그럼 또다른 예제를 봅시다
try
{
throw 1; 또는 throw "안녕";
}
catch(char *s)
{
printf("[%s]char*형으로 예외처리가 들어왔군!\r\n", s);
}
catch(int s)
{
printf("[%d]int형으로 예외처리가 들어왔군!\r\n", s);
}
자 결과는 throw 1을 사용할경우 정수형이니깐 catch할때 정수형에 맞춰서
int형으로 예외처리가 들어왔군!''라고 결과를 출력하게 됩니다.
throw "안녕" 일경우에는 스트링으로 예외처리를 발생시켰으므로 catch의 char*형을 찾아가
char*형으로 예외처리가 들어왔군!''라고 결과를 출력하게 됩니다.
아주 간단하죠 throw의 exception type이 catch의 인자와 유형이 똑같아야 catch에서 예외처리를
받아 들이게 됩니다? 아셨죠?
만약 다음과 같이 인자의 형이 틀리게 되면 어떡해 될까요?
try
{
throw 1;
}
catch(char *s)
{
printf("[%s]char*형으로 예외처리가 들어왔군!\r\n", s);
}
아까 위해서 말한 시스템 함수인
terminate()가 호출되어 abnormal program termination 에러가 발생하여 종료 됩니다.
throw의 예외처리 값이 1이 들어갔는데 catch에는 char*형뿐이 없으니
예외처리를 찾을 수 없게 되어 결국은 디폴트값으로 시스템 제공 함수인 terminate()이 호출되어
프로그램이 종료됩니다.
아셨죠?
또는 바깥에 함수를 만들어서 호출하여 예외처리를 발생 시킬수 있습니다.
void f() throw()
{
throw 1;
}
void main()
{
try
{
f(); //함수를 호출하여 예외처리를 발생시킵니다
}
catch(int s)
{
printf("[%d]int형으로 예외처리가 들어왔군!\r\n", s);
}
}
또다른 예제를 봅시다
try
{
throw "방가워";
}
catch(char*)
{
printf("하이");
}
자 이방식은 char*에 유형만 주고 아까처럼 char *s변수로 받는것은 넣지 않았죠
이렇게 유형으로만 예외처리를 발생시킬 수도 있습니다.
그리고 throw에 클래스를 넣어 예외처리를 발생 할 수 있습니다.
그것도 방식은 똑같습니다. 한번 직접 코딩해보시기 바랍니다.
이상 간단한 예외처리 팁이였습니다. 그럼 수고하세요!
출처 : kv20님의 글
(수정일 : 2007년 12월 27일)