항목 17에서 객체의 생명주기와 예외의 관련성에 대해서 이야기 했다면, 이번 항목에서는 객체 생성자에서 발생된 예외는 어떻게 진행되며, 어떻게 처리 해야 좋을 지에 대한 고민을 하는 항목이다.

질문 1. 항목 17의 예제 1에서 A나 B의 생성자가 예외를 발생시키면 C의 생성자가 그 예외를 흡수해서 예외를 아예 발생하지 않게 하는 것이 가능한가? 예와 함께 왜 이런 식으로 되었는지에 대한 근거를 제시하라.

질문 2. C의 생성자(들)에 안전하게 빈 throw 정의를 넣을 수 있도록 A와 B가 지켜야 하는 최소한의 요건은 무엇인가?


해설

질문 1.

해당 질문에 답하기 위해선 표준 예외 발생에 대한 규정을 알고 있어야 할 듯 싶어, 책에서 몇가지 규칙을 설명해 준다.

1.  핸들러가 단순히 'return;' 할 수 없다. MSVC 2005 경고 최고수준인데도 아무런 경고도 없음,

예제코드




2. 핸들러가 'throw;' 라고 하면 A::A() 나 B::B()가 애초에 발생된 예외를 다시 발생시킬 것이다.

예제 코드


3. 핸들러가 다른 예외를 발생 시키면, C 생성자에서 catch 한 예외가 아닌 C 에서 발생 시킨 예외가 캣취 될 것이다.

예제코드



4. C++ 표준에는 분명히 규정 되어 있지만, C의 catch() 에서 예외를 발생시키지 않으면, throw 한것과 똑같이 원래 발생 되었던 예외가 밖으로 나가게 된다.

예제 코드



총 정리 하자면, C의 try 핸들러(catch)가 예외를 발생시키지 않는다면, 본래의 예외를 밖으로 던지거나, 다른 예외로 바꾸어서 던질 수 밖에 없다.왜냐하면 중요. "생성자에선 예외가 발생되면, 무조건 예외가 밖으로 빠저나가기 때문이다"

예제 코드

결국 생성자에서 발생 된 예외는 그 어떤 생성자라도 정신줄을 놓게 만든다는 의미이다. : ) 만약 그 성생된 개체 없이 포장한 개체(즉 C 클래스 같은 개체)의 내부 개체가 없어도 그런데로 꾸려 갈 수 있다면, pimpl 이디엄을 이용하여, 좀 견고한 코드를 짤 수 있다고 책에선 말하고 있다.( .., 음 이건 좀 관리하기 까다롭겠군. )

자, 질문에 답해 보자. 예외를 생성자에서 흡수 할수 없다. 위에서 예제코드로 본대로 말이다. 왜 이렇게 만들 수 밖에 없었냐면, 예외 처리로 들어온 시점에 객체의 멤버 또는 상속형 멤버 개체들은 모두 그 개체에 속한 지역 변수들이다. 그러므로, 예외 블록 핸들러 내부에 들어온 시점에서 소멸자가 호출되어졌다는 것을 의미한다.

결국 생성자의 부수적인 예외처리는 각 객체의 소멸자에게 책임을 떠 맞기는게 관리적인 측면이나 개발적인 측면이나 모두 알맞다고 볼수 있다.

참, 소멸자 내부에선, 예외 흡수가 가능하다. 책에선 안된다고 하지만, 오역이다.

질문 2.

.. 질문 1에서 보았다 시피, A와 B에서 지켜야할 최소 사항은 아예 예외를 발생 시키지 않아야 하는 조건이 있어야 한다. ... 그럴거면 C에서 모하러 throw 하겠는가? 어차피 생성자에서 발생된 예외는 생성자에서 처리 할 수 없으므로(처리 자체가 안된다.), 생성자 try catch 는 전혀 필요가 없다;

왜냐하면 생성자에서 발생한 예외를 처리 하기 위해서 결국 외부에서 다시 try catch 를 쳐야 하기 때문이다.


총평

대체적으로 각 부위마다 테스트를 해보면서 이해 했었다. 생성자에서 발생된 예외를 생성자에서 처리 할 수 없으니 밖에 친 try 에 맞기되, 동적 메모리 힐당으로 얻은 객체에 대해서 손쓸 방법이 애내하니, 내부 소멸자에 의해서 처리 하게 하는게 좋겠다 싶은 생각을 만들어 주는 항목이 아닐까 한다. ... 흠~


posted by 농사를 짓는 게임 프로그래머 최익필

댓글을 달아 주세요