暗黙のエラーチェックを実現する
動機
APIなんかで、よく
bool GetSomeValue(type param1,type param2,type* result);
式の関数を見かける。引数で結果を格納する場所を渡し、「成功したかどうか」を返値とするやつ。
エラー処理をまじめにやると
bool result; type value; result=GetSomeValue(1,2,&value); if(!result) { /* エラー処理 */ } result=DoSomething("hoge","hage",value); if(!result) { /* エラー処理 */ } result=DoAnotherSomething(value); if(!result) { /* エラー処理 */ } //...
といったかんじになって大変うざいわけですね。
提案手法
class unchecked_error {}; struct succeed { succeed(bool succeed):succeed_(succeed),checked_(false) {} operator bool() { checked_=true; return succeed_; } ~succeed() { if(!succeed_ && !checked_) throw unchecked_error(); } private: bool succeed_; bool checked_; };
というクラスを用意して、処理の成否をこれで表現することにする。
succeed GetSomeValue(int* p) { if(!p) return succeed(false); *p=100; return succeed(true); }
int main() { int n; GetSomeValue(&n); //失敗を想定しない場合、エラーチェックする必要はない。 bool result=GetSomeValue(0); if(!result) cout << "エラー" << endl; //if(GetSomeValue(0)) ... でもよい GetSomeValue(0); //throws unchecked_error exception }
見られていない戻り値を自動チェックし、エラーがあった場合に例外を投げてくれる。
問題
代入時のコピーコンストラクタ周りの挙動を理解していないため、処理系によってはひどいことになる可能性。
あと実装をよく理解して使わないと死ぬ(実行時に)。