質問には言語タグはありませんが、おそらく暗黙のうちに「コーヒー言語」について話していることを理解しています。しかし、完全を期すために、C ++の世界では見かけ上のコンセンサスが多少異なっていることに言及したいと思います。
C ++プログラマーが通常関心を持っているのは、次の3つのことです。
- 最適化されたビルドでオーバーヘッドがゼロになりますか?(つまり、「コンパイル」できますか?)
- エラーが検出された時点でデバッガーにトラップするために使用できますか?
- 宣言された関数の問題を報告するために使用できます
noexcept
か?
過去に、私はこのようなコードを書くことで最初の問題に取り組みました
int
factorial(const int n)
{
if (CHECK_ARGS)
{
if (n < 0)
throw std::invalid_argument {"n < 0"};
}
int fac = 1;
for (int i = 2; i <= n; ++i)
fac *= i;
return fac;
}
どこで CHECK_ARGS
で、#define
dはコンパイル時の定数であるため、コンパイラは最適化ビルドのすべての引数チェックコードを完全に削除する場合があります。(チェックアウトをコンパイルすることは一般に良いことだと言っているわけではありませんが、ユーザーがチェックアウトするオプションを持っているべきだと思います。)
引数をチェックするコードがはっきりと見えるようにグループ化されているというこのソリューションについてはまだ気に入っています if
ます。ただし、2番目と3番目の問題はこれで解決されません。したがって、assert
引数のチェックにマクロを使用する方向に再び傾いています。
の コーディング標準ブーストはこれに同意します:
プログラマーのエラーはどうですか?
開発者として、使用しているライブラリの前提条件に違反した場合、スタックを巻き戻したくありません。私が欲しいのは、コアダンプまたは同等のものです。問題が検出された正確なポイントでプログラムの状態を検査する方法です。それは通常、assert()
またはようなものをします。
CppCon'14でJohn Lakosによる「Defensive Programming Done Right(part 1、part 2)」というタイトルの非常に興味深い講演がありました)。彼の講演の最初の部分で、彼は契約の理論と未定義の行動について議論します。第二部では、体系的な議論チェックのための非常に良い提案と私が考えるものを提示します。本質的に、彼は、ユーザーが引数チェックのためにライブラリに寄付したい予算の量を選択できるアサーションマクロを提案し、ライブラリにその予算を賢く使用させます。また、ユーザーは、破損した契約が検出された場合に呼び出されるグローバルエラー処理関数をインストールすることもできます。
関数がプライベートであるという側面に関して、これは引数をチェックしないようにする必要があるとは思わない。内部関数の規約に違反しないように、独自のコードをより信頼するかもしれませんが、私たちも完璧ではないことも知っています。内部関数の引数チェックは、クライアントコードのバグを検出するパブリック関数と同様に、独自のバグを検出するのに役立ちます。