기본 문법 : throw

// throw
    if (index >= size_) {
      throw out_of_range("vector 의 index 가 범위를 초과하였습니다.");
    }

표준 exception 객체들은,

객체는 대부분 exception 내용을 포함하는 string 으로 구성되어 있다. exception 객체를 만들고 싶으면,

class MyException : public std::exception
{
public:
    virtual const char* what() const noexcept override { return "My Exception!!\n"; }
}

exception 을 throw 하면?

잠깐, stack unwinding

main -> func1 -> func2 -> func3 순으로 수행하는데 func3 에서 exception 을 던지면 (throw), func1, func2 는 func3() 호출부 이후의 코드를 수행하지 않는다. 이건 try catch 가 없어도 똑같이 작동하는데, 위에서 언급한 ‘함수를 하나씩 종료시키다가 catch 에서 잡았다’ 라는 논리라면, 코드 상에서 func3 에 대한 exception 을 처리할 수 없는 상황이 func2, func1 에 있는데도 이후 코드가 작동되지 않는 것은 말이 안 된다. 즉, catch 로 바로 점프하면서 스택에 할당된 객체를 모두 소멸시켰다고 보는 해석이 더욱 직관적이고, 그것이 사실이다.

생성자에서 exception throw

가급적 안 해야겠지만, 필연적으로 할 수 밖에 없다면 주의. 바깥에서 catch 를 했다 하더라도 생성자에서 할당받은 영역은 스택 영역이 아니므로 stack unwinding 을 못 한다. 따라서 생성자 내부에서 catch 를 해서 소멸을 다 시켜준 다음 한번 더 던져야 한다. (안 던지면 바깥에서는 모른다. 주의!)

클래스에서의 catch

단순 exception 을 방출하는 Parent / Child 가 있을 때, catch 를 Parent 로 ‘먼저’ 해버리면 Child 도 여기서 catch 된다. super class 니까, 이런 구문이 성립할 수 있는 것이다.

Parent& p = Child();

// 따라서
  catch (Parent& p) { // Parent, Child 모두 여기서 걸린다.
    cout << "Parent Catch!" << endl;
    cout << p.what();
  } catch (Child& c) {
    cout << "Child Catch!" << endl;
    cout << c.what();
  }