1

プログラムは:

#include <stdio.h>

struct foo
{
   void blah()  {printf("blah\n");}
   int i;
};

void main(int, char**)
{
   ((foo*)NULL)->blah();
}

blahあなたが知っているコンパイラで、クラッシュしたり、 output 以外のことをしたりしたことがありますか? メンバー (vtable を含む) にアクセスしない場合、NULL ポインターを介して呼び出されたときに関数がクラッシュしますか?

このトピックについては他にも質問がありました。たとえば、NULL ポインターでクラス メンバーにアクセスすることや、ヌル ポインターを介してメンバーにアクセスしない非静的メソッドを呼び出すことは合法的/適切に定義された C++ ですか? 、これにより未定義の動作が発生することが常に指摘されています。しかし、これは現実の世界では未定義ですか、それとも標準の世界だけですか? 期待どおりに動作しない既存のコンパイラはありますか? 将来のコンパイラが期待どおりに動作しないもっともらしい理由を思いつきますか?

関数メンバーを変更するが、NULL ptr が保護されている場合はどうでしょうか。例えば、

void foo::blah()
{
   foo* pThis = this ? this : new foo();
   pThis->i++;
}

編集:記録のために、私がこれを望んだ理由は、リンクリストクラスへのインターフェースをできるだけ簡単かつ簡潔にすることでした。リストを NULL に初期化したいのですが、慣用的な使い方は次のようになります。

pList = pList->Insert(elt);
pList = pList->Remove(elt);
...

すべての演算子が新しい head 要素を返す場所。どういうわけか、コンテナー クラスを使用すると、マイナス面がなく、物事がさらに簡単になることに気づきませんでした。

4

3 に答える 3

2

守ろうとしてthis == NULLも、本当に望ましい効果は得られません。主に逆参照NULLポインター、AFAIK はundefinedです。コンパイラによって動作が異なります。1 つのシナリオ (このような) で機能するとしましょう。このシナリオまたはこれ(仮想関数) では機能しません。2 番目と 3 番目のシナリオは、どの仮想関数を呼び出すかを確認するための vtable エントリがインスタンスにないため、理解できます。しかし、最初に同じことが言えるかどうかはわかりません。

考慮する必要があるもう 1 つのことは、無効なポインターは、この のように、保護したいのと同じ種類のエラーを与える可能性があることです。'Foo' が正常に出力された後、 にアクセスしようとしてランタイム エラーが発生したことに注意してくださいa。これは、 が指しているメモリ位置Test* tが無効であるためです。がの場合、ここでも同じ動作が見られます。Test* tNULL

したがって、一般的には、そのような動作を避け、コードで設計してください。これは予測不可能であり、誰かがあなたの後を追ってきて、以前と同じように振る舞うべきだと考えてあなたのコードを変更すると、望ましくない結果をもたらすでしょう。

于 2013-07-01T21:44:09.080 に答える