2016-04-27 6 views
2
#include <iostream> 
int main() 
{ 
    int *ptr = NULL; 
    // It does not crash 
    *ptr; --------> Point-1 
    //But this statment crashed 
    std::cout<<"Null:"<<*ptr<<"\n"; ------> Point-2 
    return 0; 
} 

上記のコードでは、 "Point-2"とコメントしてもコードはクラッシュしません。 しかし、「Point-2」をコメント解除すると、クラッシュします。 ptrがNULLなので、理想的にはPoint-1もクラッシュするはずです。もし私が間違っているなら、私に連絡してください。 誰かがなぜ私は単純にポインタをderefferneceするときにコードがクラッシュしなかったのか説明することができますか?なぜ単にNULLを割り当てられたポインタを参照解除するとクラッシュしない

+2

デバッグモードで最適化を行わずにコンパイルして、もう一度やり直してください。 – BlackBear

+2

*定義されていない動作*が発生すると仮定して停止します。それはしません。事実、もしあなたが*運が良ければ、それはクラッシュし、本当になぜそれが本当であるのかを理解したいと思ってほしいのです。 – WhozCraig

+2

参考: - http://stackoverflow.com/questions/12645647/what-happens-in-os-when-we-dereference-a-null-pointer-in-c – ravi

答えて

2

ヌルポインタの参照解除は未定義の動作です。未定義の振る舞いはエラーと同じではありません。定義されていない動作を引き起こした場合、何かが起きる可能性があります。他の方法を求めている場合:

なぜ私たちに奇妙な動作を与えるのではなく、未定義の動作でエラーが発生しないのですか?

多くの理由が原因である可能性があります。 1つの理由はパフォーマンスです。たとえば、std::vector(少なくともMSVC)の実装では、リリースモードでインデックスがの範囲外である場合、インデックスがであるかどうかはチェックされません。これを試すことができます:

std::vector<int> v(4); 
v[4]=0; 

コンパイルして実行します。あなたは奇妙な行動を取るか、そうでないかもしれません。ただし、デバッグモードでは、実行時に例外がスローされます。デバッグモードではパフォーマンスが重要ではないため、MSVCはデバッグモードでチェックを行います。しかし、パフォーマンスが重要なため、リリースモードではありません。

nullポインタの逆参照にも同じことが適用されます。次のことができます逆参照のコードは次のようにラッパーに置かれることをイメージ:

//Imaginary code 
T& dereference(T* ptr){ 
    if(ptr==nullptr){ 
     throw; 
    } 
    return *ptr; 
} 

この部分:if(ptr==nullptr){throw;}が望ましくない状況で、すべてのポインタの参照解除のプロセスが遅くなります。

しかし、それは次のように行うことができる。

//Imaginary code 
T& dereference(T* ptr){ 
    #ifdef DEBUG 
    if(ptr==nullptr){ 
     throw; 
    } 
    #endif 
    return *ptr; 
} 

私はあなたが今、アイデアを得たと思います。

+0

私は、「未定義の振る舞いはクラッシュに等しくない」と2番目の文で言います(それはエラーです - 必ずしもそうではありません捕らえられるエラー)。 –

+0

あなたが言うことは真実ですが、この特定のケースでは、アクセスが最適化されているためにアクセスが行われていないと思います。 –

+0

@MartinBonner mmm私は本当に知りません..エラー、定義によって、何かが間違っていますか?少なくともそれが引き起こされるべきではありませんか?私はキャッチされたことを意味しなかった、ちょうど引き起こされた?未定義の動作は何もトリガしません。右? –

0

ポイント2で、アクセス違反エラーを生成する0x0アドレスの内容を表示しようとします。

ポイント1では何もしないので、プログラムはこのポインタで記述されたメモリにアクセスする必要はありません。これにより、アクセス違反エラーは発生しません。

+0

これがなぜ投票されなかったのか分かりません。私はそれがまさに正しいと思う。 –

+0

@MartinBonnerプログラムがメモリにアクセスする必要がない理由を説明しません。たとえば、NULLポインタの参照解除に何らかの動作が定義されていた場合、アクセスを削除して最適化することは不正です(取得する予定の動作を取得しないため)。これは、UBでアクセスを削除できるためです。 –

+1

@DavidSchwartz:それは間違っています。非揮発性へのポインタの逆参照は副作用がないので、アクセスを最適化することができます。 UBとはまったく関係がありません。コードが 'int i = 42、* ptr =&i;であれば、 * ptr; '、コンパイラは依然としてアクセスを最適化できました。 –

関連する問題