new 연산자에 의해서 발생하는 예외


- new 연산에 의한 메모리 공간의 할당이 실패하면 bad_alloc이라는 예외가 발생한다. 

bad_alloc은 헤더파일 <new> 에 선언된 예외 클래스로써 메모리 공간의 할당이 실패했음을 알리는 의도로 정의되었다.



위 예제에서 보이듯이 프로그래머가 정의하지 않아도 발생하는 예외도 있다. 






모든 예외를 처리하는 catch 블록



마지막 catch 블록에 덧붙여지는 경우가 많은데, 대신 catch의 매개변수 선언에서 보이듯이, 발생한 예외와 관련해서 그 어떠한 정보도 전달받을 수 없으며, 전달된 예외의 종류도 구분이 불가능하다. 







예외 던지기


- catch 블록에 전달된 예외는 다시 던져질 수 있다. 

그리고 이로 인해서 하나의 예외가 둘 이상의 catch블록에 의해서 처리되게 할 수 잇다. 




예외처리는 가급적 간결한 구조를 띠는게 좋다. 따라서 정말로 필요한 상황이 아니라면, 굳이 예외를 다시 던지기 위해서 노력할 필요는 없다. 


Posted by scii
:

클래스의 객체도 예외 데이터가 될 수 있다. 그리고 이것이 일반적인 방법이다.



예외 클래스와 예외 객체


예외발생을 알리는데 사용되는 객체를 가리켜 '예외객체'라 하며, 예외객체의 생성을 위해 정의된 클래스'예외 클래스'라 한다.

그리고 객체를 이용해서 예외상황을 알리면, 예외가 발생한 원인에 대한 정보를 보다 자세히 담을 수 있다.



54행: 예외객체를 전달하는 일반적인 방법을 보이고 있다. 어차피 예외객체는 C++의 예외처리 메커니즘에 의해 처리되기 때문에 코드상에서 이를 직접 참조할 필요가 없다. 

따라서 예외객체는 임시객체의 형태로 생성하는 것이 보통이다.


예외 클래스라고 해서 특별히 다른 것은 없다. 다만, 해당 예외상황을 잘 표현할 수 있도록 정의하면 된다.

그리고 너무 복잡하게 정의하지 않는 것이 좋다. 예외의 표현을 위한 최소한의 기능만 담아서 정의하면 된다.







상속관계에 있는 예외 클래스


- 예외 클래스도 상속의 관계를 구성할 수 있다.




56행: 상속에 의해서 DepositException 객체도 AccountException 객체로 간주가 되기 때문에 이러한 선언이 가능하다.


위에서 보이듯이 상속을 통해서 예외 클래스를 묶으면, 예외의 처리를 단순화시킬 수 있다. 물론 이것이 항상 좋은 것은 아니지만, 단순화해도 되는 상황에서는 유용하게 활용될 수 있다.







예외의 전달방식에 따른 주의사항 


- 예외가 발생하면, 해당 예외 데이터를 전달받을 수 있는 catch 블록을 위에서 아래로 찾아내려 간다. 그리고 적절한 catch 블록을 찾게 되면, 해당 catch 블록이 실행되면서 예외의 처리는 완료가 된다.


# catch 블록이 잘못된 예


위 예제의 문제점은 모든 예외 객체가 AAA 클래스를 상속하기 때문에, 45행의 catch블록이 실행된다는데 있다. 

즉, 위와 같은 구조로 catch 블록을 구성하면, 50, 55행의 catch 블록은 실행되지 않는다. 

내가 원하던 것은 "BBB 예외객체는 catch(BBB& expn) 블록에 의해서 처리가 되고, CCC 예외객체는 catch(CCC& expn) 블록에 의해서 처리가 되게끔 하고 싶었던 것이다."



내가 원하던대로 하게 하려면, catch블록의 배치를 변경해야 한다.




BBB 객체는 일종의 AAA 객체이지만, AAA 객체는 일종의 BBB 객체가 아니다. CCC도 마찬가지.

그렇기 때문에 원하는 결과를 얻을 수 있다.



Posted by scii
:

C++에서 말하는 '예외(Exception)' 는 프로그램의 실행 도중에 발생하는 문제상황을 의미한다.

따라서 컴파일 시 발생하는 문법적인 에러는 예외의 범주에 포함되지 않는다.


ex) 나이를 입력하는데 0보다 작은 값이 입력되었다.

       나눗셈을 위한 두 개의 정수를 입력 받는데, 제수로 0이 입력되었다.

       주민등록번호 13자리만 입력하라고 했더니, 중간에 -를 포함하여 14자리를 입력하였다.


이렇듯 '예외' 라는 것은 문법적인 오류가 아닌, 프로그램의 논리에 맞지 않는 상황을 의미한다.



0으로 나누는 연산은 불가능하므로, 프로그램이 강제로 종료되어버린다.


예외가 발생하면, 그에 따른 처리가 이뤄져야지, 위의 실행결과에서 보이듯이 그냥 프로그램이 종료되어버리는 상황을 만들어서는 안 된다.






if 문을 이용한 예외의 처리




if문을 이용한 예외처리는 "에외처리를 위한 코드와 프로그램의 흐름을 구성하는 코드를 쉽게 구분하지 못하게 한다."


※ if문이 등장하면 에외처리를 위한 코드라고 생각하고, 주석을 달 수 있다.

하지만! 프로그램의 논리적인 기능의 완성을 위해서도 if문은 사용된다. 그리고 예외가 아닌 다른 정보의 기록을 위해서도 주석은 사용된다.

즉, if문과 주석만을 사용해서는 딱 보고 예외처리라고 판단할 수 없다.






C++ 의 예외처리 메커니즘


- C++ 은 구조적으로 예외를 처리할 수 있는 메커니즘을 제공한다. 이 메커니즘을 이용하면, 코드의 가독성과 유지보수성을 높일 수 있다. 

예외의 처리를 프로그램의 일반적인 흐름에서 독립시키는 것이 가능하기 때문이다.


try          예외를 발견

catch         예외를 잡는다.

throw        예외를 던진다.




try 블록

- try 블록은 예외발생에 대한 검사의 범위를 지정할 때 사용된다. 즉, try 블록 내에서 예외가 발생하면, 이는 C++의 예외처리 메커니즘에 의해서 처리가 된다.


try

{

// 예외발생 예상지역 

}


catch 블록

- catch 블록은 try 블록에서 발생한 예외를 처리하는 코드가 담기는 영역으로써, 그 형태가 마치 반환형 없는 함수와 유사하다.


catch(처리할 예외의 종류 명시)

{

// 예외처리 코드의 삽입

}


throw

- 키워드 throw는 예외가 발생했음을 알리는 문장의 구성에 사용된다.

- ex) throw expn;

expn은 변수, 상수 그리고 객체 등 표현 가능한 모든 데이터가 될 수 있으나, 예외상황에 대한 정보를 담은, 의미 있는 데이터이어야 한다. 그래서 위 문장에서 expn의 위치에 오는 데이터를 가리켜 그냥 '예외'라고 표현하기도 한다.


※ try와 catch는 하나의 문장이다. 따라서 항상 이어서 등장해야 한다.

따라서, try 블록 내에서 발생하는 예외는 이어서 등장하는 catch 블록에 의해 처리된다.


=> throw에 의해 던져진 '예외 데이터'는, '예외 데이터'를 감싸는 try 블록에 의해서 감지가 되어 이어서 등장하는 catch 블록에 의해 처리된다.



즉, 예외가 발생하면(throw 절이 실행되면), 프로그램의 흐름이 중지되고, catch 블록에 의해서 예외의 처리과정을 거치게 되는데 이것이 바로 C++ 의 예외처리 메커니즘이다.




try 블록 내에서 예외가 발생하면, catch 블록이 실행되고 나서, 예외가 발생한 지점 이후를 실행하는 것이 아니라, catch 블록의 이후가 실행됨을 보인다.

이렇듯, 예외가 발생하면, 예외가 발생한 지점 이후의 나머지 try 영역은 그냥 건너뛰게 된다.


그리고 throw절에 의해 던져진 예외 데이터의 자료형과 catch 블록의 매개변수 자료형은 일치해야 한다. 만약 일치하지 않으면, 던져진 예외 데이터는 catch 블록으로 전달되지 않는다.






try 블록을 묶는 기준


- try 블록을 만나면 그 안에 삽입된 문장이 순서대로 실행된다.

- try 블록 내에서 예외가 발생하지 않으면 catch 블록 이후를 실행한다.

- try 블록 내에서 예외가 발생하면, 예외가 발생한 지점 이후의 나머지 try 영역은 건너뛴다.


묶는 기준 : 예외가 발생할만한 영역만 묶는 게 아니라, 그와 관련된 모든 문장을 함께 묶어서 이를 하나의 '일(work)' 의 단위로 구성하는 것이다.


"try 블록 내에서 예외가 발생하면, 예외가 발생한 지점 이후의 나머지 try영역은 건너뛴다."

Posted by scii
: