try-catch

if-else와 try-catch가 다른 점은 try 구문에서 예외가 throw되면, 그 즉시 그 블럭이 종료되고 catch 블럭으로 제어가 이동된다는 점입니다. 다른말로, try블럭은 '블럭'이고, if-else는 '구문'이라는 점이 다르다는 것이죠.

예를 들어보죠.

ifstream infile( "not_exist_file_name" );
if ( infile.fail() )
{
getline( infile, s ); // 올바른 코드. 그러나 런타임 에러

// 파일이 발견되지 않았을때의 처리 코드

return;
}

if-else로 에러를 처리할 경우의 문제는 위와같이, 에러가 발생한 객체에 대해서 수명이 유지되기 때문에 에러를 처리하는 동안에도 에러가 발생한 객체를 참조하는 코드가 정상적으로 컴파일된다는 점입니다.
그러나 동일한 코드를 try-catch구문으로 바꾸면 다음과 같아집니다.

try
{
ifstream infile( "not_exist_file_name" );
if ( infile.fail() )
throw file_not_found_exception;
}
catch ( file_not_found_exception e )
{
getline( infile, s ); // 에러!! infile객체는 스코프를 벗어난 개체.

// 파일이 없을때의 처리 코드.
}

if-else구문에 비하면 훨씬 안전한 코드가 됩니다. 즉, 에러가 발생한 객체는 예외를 발생시킴과 동시에 try블럭 안의 모든 객체는 스코프를 벗어나 참조할 수 없게 되므로 예외를 처리하는 동안 try블럭 안에서 예외를 발생시켰을 수 있는 객체의 참조를 원천적으로 막아 더 안전하고 깔끔한 예외처리를 할 수 있는 환경을 만들어줍니다.


그리고 예외를 던질 때에 예외 객체의 클래스를 적절히 구성하면, 예외 객체에 예외를 처리하는 방법을 담아서 던질 수도 있습니다. 그렇게 구성하면 굉장히 깔끔한 코드를 얻을 수 있죠. 위와 같은 경우,

class file_not_found_excetion
{
void handle_exception();
};

try
{
ifstream infile( "not_exist_file_name" );
if ( infile.fail() )
throw file_not_found_exception;
}
catch ( file_not_found_exception e )
{
// 파일이 없을때의 처리 방식을 file_not_foune_excetion 클래스에 정의함.
e.handle_exception();
}


위와 같이 하면 예외가 던져지면 그 예외를 받아서 일관된 방식으로 처리할 수 있는 매커니즘이 만들어집니다. 자바의 예외처리는 Exception클래스에서 상속받거나, 혹은 Throwable 인터페이스를 구현한 클래스의 객체만이 예외로 던져질 수 있어서 위와같은 예외객체에 예외 처리에 대한 정보를 담아서 던지는 처리방법을 장려하는 언어가 되었습니다. C++에서는 모든 타입의 개체가 예외로 던져질 수 있어서 결과적으로 예외 처리에 잔손이 많이 가게 만들어서 잘 안쓰이게 되었습니다만, 적절히 구성한다면 매우 편리한 에러처리를 구현할 수 있습니다.

for와 while의 차이입니다. (모든 for문은 while문으로 변경가능함!)

그냥 좀더 코딩좀 쉽게(편하게) 해보자는 것이지요.

C에서 에러체크를 할때 대부분 리턴값이나 함수에 인자를 넘겨 그 값을 확인하여

if문으로 에러처리를 합니다.

리턴값으로 확인하는건 사실 귀찮지 않습니다.

if ( 함수호출[비교] )
{

}

이정도의 코딩이니깐요... 하지만 리턴값으로 에러를 확인할수 없는 경우도 가끔

있습니다. 이때는 인자를 넘겨야하죠..

게다가 리턴값만으로 정확히 어떤 이유에서 에러가 났는지 정확히 알기도 힘들구요..

하지만 try~ catch문은 이러한 단점을 커버해줍니다.


...

그렇다고 try~catch문이 꼭 에러처리하는데 if문보다 더 좋다고는 못합니다.

이것 때문에 메모리 누수등의 예기치 못한 에러가 날수도 있거든요..

C++에서는 상당히 신중히 쓰셔야할 키워드입니다.

컴파일러의 관점에서요.

우선 try-catch문을 지원하기 위해 컴파일러는 몇가지 정보를 유지합니다.
다는 잘 모르겠고, 가장 중요한 내용 하나만 이야기하겠습니다.

활성 스택에 생성되는 지역 객체들의 자동 소멸을 위해서
그것의 정보들을 유지합니다. (따라서 if문의 에러처리와는 달리 지역 객체들의
소멸자가 자동으로 호출되므로 메모리등 리소스 누수의 문제를 조금이나마 해결할 수
있습니다. 물론 해당 객체의 소멸자가 예외 상황까지 고려하여 제대로 코딩되었다는
가정 하에서 말이죠)

이런 저런 이유로 try-catch문은 유지해야 하는 정보도 많고 또 실제
예외가 발생했을 때도 해주어야 할 일이 많기 때문에 당연히 코드 크기나
예외 발생시 처리 속도는 if .. else if의 전통적인 반환값을 통한
오류 처리와는 비교하기 힘든 것이 사실입니다만,

또 그만큼 정보를 유지한다는 것은 그만큼 자동으로 해주는 일이 많다는
것입니다. 그러한 작업 중에는 우리가 직접 할 수 없는 작업도 있을 것이고,
설사 그 일을 우리가 전부 할 수 있다손 치더라도 컴파일러가 자동으로 생성해낸
코드보다 효율이 높다고는 장담할 수 없습니다.

또한 문법적인 측면으로 try-catch 문을 사용한 예외 처리는 자바에서 보듯이
예외 지정 (throws IOException 같은..) 등을 통해 좀 더 고급스러운
프로그램 디자인을 가능하게 합니다.

음. More Effective C++의 예외에 관련된 장을 참고하시기 바랍니다.

댓글 없음: