system_error

次のネタの準備として、C++TR2候補のsystem_errorもどきを実装しています。
↓system_errorの定義はこれです。
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2066.html


↓Boostでの実装はこちら
http://boost.cvs.sourceforge.net/boost/boost/boost/system/system_error.hpp?revision=1.1&view=markup
この実装を見てみると、what()用のバッファ文字列がmutableになっていて、what()の中で初期化されるようになっています。
不思議に思って、なんでこうなっているか考えてみました。


例外を投げるとき、まず例外オブジェクトがスタック上に構築され、投げる瞬間に「どこか」にコピーされ、(参照で受ければ)catch節ではこのコピーされた例外オブジェクトを受けることになります。
もし、例外オブジェクトのコピーで例外が発生すると、terminate()が呼び出されて異常終了します。
これを防ぐため、Boost.Filesystemの例外はメンバをshared_ptrで持たせて、コピーで例外が発生しないようになっていました。


で、今回のsystem_errorの場合、これは例外を投げる時や受け取る時、メンバのstringがまだ空のままです。
空の文字列のコピーで例外が発生しないことが保障されているか定かではありませんが、このオブジェクトのコピーで例外が発生することはまずないでしょう。
その後、what()が呼ばれて文字列が設定されますが、これは「どこか」にコピーしたオブジェクトです。
その後、再throwされても、もうオブジェクトのコピーは発生しないから安心、ということでしょう。
かなり怪しい実装な気がしますが、一応セーフかな。
あとは、親クラスruntime_errorの中の文字列がどう扱われるかが現時点では実装依存なのが気になるところです。
大抵の実装がstd::stringをメンバに持たせているので、この問題にこだわっても意味がなかったりしますし。
全部std::exceptionから継承するのも変ですよねぇ。
う〜む。