- assert で示されている条件は,正しくプログラムが書けている場合,必ず成立する
- 状況次第で失敗する可能性のある条件を assert にかけてはならない
- 例として,ユーザ入力や設定ファイルの妥当性検証を assert で行なってはならない
- 例外にするべきか assert にするべきか迷った場合には,とりあえず例外を使うことを検討する
- どの例外を投げるのが相応しいかを考える過程で,思考が整理されることが期待できる
- 思考整理ができなかった場合には,その旨をソースコードや pull req. のコメントに残す
- 例外送出を assert にするのは容易だが,逆は容易でない
- どの例外を投げるのが相応しいかを考える過程で,思考が整理されることが期待できる
- ローカル変数, private メンバ変数,ファイルスコープ変数など,
アクセスできる範囲が「閉じている」ものに対して不変条件のチェックを行う場合
- それらの変数は,単体テストで不変条件をチェックしにくいため, assert を使ってチェックすることが望ましい
- 例として,二つのポインタを管理しているクラスで,それらのポインタは 常に同時に(非 NULL の値に)設定され,常に同時に NULL にクリアされるような場合には, 片方のみが NULL になることは ありえないため, assert を使ってチェックすることが望ましい
- バグの存在を,もみ消されることなく 即座に検出したい場合
- 例として,外部ライブラリの関数を呼び出した結果に対し,何らかの条件の成立が期待される場合, 期待した通りにならないケースでは,その関数の仕様を勘違いしている可能性が高いため, assert を使って即座に勘違いを検出できるようにすることが望ましい. (もちろん,状況次第では失敗することが期待され,失敗すると処理を続行できない場合には, assert を使わずに runtime_error を投げることで失敗を通知することが望ましい)
- コメント代わりに使うことで,コーディング上の不安を取り除きたい場合
- 例として,
sqrt(x)を呼ぶ際,「バグがなければ必ずxは 0 以上になるが,その事実は パッと見では分からない」ような場合には,// x >= 0のようなコメントを書くよりassert(x >= 0);と書いたほうがよい(ASSERT_GTのようなマクロがあれば,それを使う) - 同様に,関数末尾に
// this function never returnsというコメントを書きたくなった場合,assert(!"this function never returns");のように書く方がよい(ASSERT_UNREACHABLEのようなマクロがあれば,それを使う)
- 例として,
- ある関数を呼び出す際に必要な事前条件のチェックには, assert を使ってもいいし,例外を使ってもいい
- 比較的単純な条件であり,かつ その関数が呼ばれる頻度が高い場合には, assert を使う
- 条件が複雑であり,事前にチェックするより「試しに実行してみる」方が楽である場合には, 例外か,もしくは optional 的なものを使ったほうがスムーズになる
- その他,例外を使った方が処理の見通しが良くなるケースには,例外を使う
- 失敗する可能性のある assert は assert ではないので書いてはいけない
- 失敗する可能性のある処理には,例えば
mallocがある. その結果は assert してはいけない
- 失敗する可能性のある処理には,例えば
if (x <= 0) { throw 〜; }に続くassert(x > 0);のような,書く必要のない assert は原則として書かない- ただし,条件をチェックする部分と assert を書きたくなった部分が 同じ画面に入りきらないくらい離れている場合は,その限りではない
- assert を書かないと不安になる程度に 複雑で入り組んだコードの場合は, assert より むしろ条件分割や関数化によって簡潔で分かりやすい条件に落とし込めないかを考える
使うべき・べきでない点についてしっかり書けていると思います。
逆にいえば、使用する上でのガイドラインではあるのでassertを使う目的・効果に関する記述ではなく、assertをチームのメンバーへ布教するには積極的に利用するメリット・モチベーションが感じられないと思います。
例えば以下のような観点から、チームでどのようにassertを利用していくとよいか、どうやったらassertを使うことで得たい効果を達成できると思いますか?