最近、constメンバー関数が操作を実行して結果を返すというケースに遭遇しました。例えば、
class Foo { ...
Foo add(Foo const & x) const;
}
しかし、他の誰かが、this
オブジェクトを更新しているように(結果を無視して)誤って呼び出していました。
Foo a = ...;
Foo b = ...;
a.add(b);
(このバグは、実際には不完全なリファクタリングによって発生しました。)
上記の最後の行でエラーまたは警告をトリガーする方法はありますか?次善の策は実行時のキャッチです。これは主に次のテンプレートで対処されます。ただし、カウンターの結果からわかるように、戻り値の最適化は無効になります。
template<typename T>
class MustTake {
T & obj;
bool took;
public:
MustTake(T o) : obj(o), took(false) {}
~MustTake() { if (!took) throw "not taken"; }
operator T&() { took = true; return obj;}
};
struct Counter {
int n;
Counter() : n(0) {}
Counter(Counter const & c) : n(c.n+1) {}
~Counter() {}
};
Counter zero1() {
return Counter();
}
MustTake<Counter> zero2() {
return Counter();
}
int main() {
Counter c1 = zero1();
printf("%d\n",c1.n); // prints 0
Counter c2 = zero2();
printf("%d\n",c2.n); // prints 1
zero1(); // result ignored
zero2(); // throws
return 0;
}
マクロを使用することで非効率性を改善できると思います。これにより、MustTake <>はデバッグのみで、リリースは不要になります。
コンパイル時のソリューションを探しています。それが失敗した場合、私は最良のランタイムソリューションを探しています。