14項 例外使用を賢く用いる

例外使用を賢く用いる



C++標準では、関数がthrow一覧にない例外をスローした場合unexpectedを呼び出す必要があります。

void throwAnyType() throw(...)
{
	throw "string";
}

void noThrow() throw() 
{
	throwAnyType(); //unexpected()
}

unexpectedのデフォルトの振る舞いはterminate()を呼び出すことなので、デフォルトのunexpectedを呼び出してはいけません。



対策は、unexpectedを上書きし、terminateを呼び出させないことです。unexpectedは、set_unexpected()で上書きできます。

unexpectedが投げる例外を指定して、処理するという方法があります。

class UnexpectedException{};

void convertUnexpected(){ throw UnexpectedException();}

set_unexpected(convertUnexpected); //unexpectedはconvertUnexpectedになる。

unexpectedの代替関数が例外を投げなおすとき、その例外はbad_exceptionになるというルールがあります。
そのルールを利用して、unexpectedが投げる例外をbad_exceptionに固定できます。

void convertUnexpected(){ throw ;} //bad_exceptionを投げる。

set_unexpected(convertUnexpected);

あとは投げられた例外を処理することで、安全を保てます。


Visual C++での実装

MSDN:unexpectedの解説の部分に、

C++ 標準では、関数が throw 一覧にない例外をスローした場合 unexpected を呼び出す必要があります。 現在の実装では、これをサポートしていません。

とあるため、現在のVisual C++ではunexpectedが呼び出されません。なので、unexpectedからterminate()が呼ばれる心配はありません。