C++ でポインターに「アサート」を使用する必要があるのはいつですか? また、使用する場合、最も一般的にはどのように実装されていますか?
7 に答える
通常、アサートを使用して条件をチェックします。false の場合は、アプリケーションのバグを示します。したがって、バグがない限り、アプリケーションのある時点で NULL ポインターに遭遇してはならない場合は、それをアサートします。無効な入力が原因で発生する可能性がある場合は、適切なエラー処理を行う必要があります。
ポインターに対して assert を使用する必要はまったくありません。アイデアは、ポインターが null のときにポインターを逆参照するときにクラッシュしないようにすることです。
でこれを行うことができますが、このassert
ようなエラーを処理するのはあまり専門的な方法ではありません。これは、常にプログラムを終了させるためです。たとえば、ユーザーが最後の 3 時間分のデータ入力を保存していない場合はお勧めできません。
ポインターに対して行うべきことは、ポインターが null であるかどうかをチェックし、正常に失敗することです。つまり、関数で何らかのエラーを返すか、何もしないようにします (誰もがこのアプローチに同意するわけではありませんが、文書化されていれば完全に受け入れられます)。
私の意見では、これは開発中に問題を検出するためのassert
ものです。そのため、一部のコンパイラではリリース ビルドで assert が何もしないことがわかります。防御的プログラミングに代わるものではありません。
それを行う方法について:
#include <assert.h>
void doSomethingWithPointer (int *p) {
assert (p != 0);
cout << *p << endl;
}
しかし、これは次のように行う方がよいでしょう:
void doSomethingWithPointer (int *p) {
if (p != 0)
cout << *p << endl;
}
つまり、「コントラクト」(API) で null ポインターの受信が許可されていないと規定されている場合でも、それらを適切に処理する必要があります。古い格言:与えるものは保守的であり、受け入れるものは寛容である(言い換え)。
ASSERT ステートメントは、「強制されたドキュメント」として優れています。つまり、コードについて何かを読者に伝え (「これは決して起こらないはずです」)、それが当てはまらない場合はそれを知らせることでそれを強制します。
発生する可能性がある場合(無効な入力、メモリを割り当てられない) は、 ASSERT を使用するときではありません。アサーションは、誰もが前提条件などに従っている場合に発生する可能性がないことのみを対象としています。
次のように実行できます。
ASSERT(pMyPointer);
経験上、通常の条件下では絶対に発生しないはずの null 条件でアサートすると、プログラムは非常に悪い状態になります。このようなヌル状態から回復すると、元の問題が隠される可能性が高くなります。
例外の保証を念頭に置いてコーディングしない限り(linky)、クラッシュさせると言うと、問題があることがわかります。
C では、assert 関数もあります。デバッグ モードでは、assert(x)、x 条件が false の場合、アラートがポップアップします。ただし、デバッグ モードでのみ機能することを覚えておいてください。リリース モードでは、すべてアサートします。関数はすべてスキップされます
null ポインターがすぐにクラッシュを引き起こすわけではありませんが、後で見つけにくい問題が発生する可能性がある ASSERT を使用します。
例えば:
ASSERT(p);
strcpy(p, "hello");
少し不要です。致命的な例外を致命的なアサートに置き換えるだけです!
しかし、より複雑なコード、特にスマート ポインターのようなものでは、ポインターが意図したものであるかどうかを確認すると便利な場合があります。
ASSERT はデバッグ ビルドでのみ実行され、リリースでは消えます。