C ++での「null参照」と「nullポインタ」の違い

C ++の「参照」と「ポインタ」の違いについては、インターネット上に多くの記事があります。違いについては、「参照をNULLにすることはできません。参照を有効なストレージユニットに関連付ける必要があり、ポインタをNULLにすることができます。 )「しかし、実際のアプリケーションでは、一貫性を維持するために、このルールを脇に置き、人工的に「null参照」を作成します。

多くの場合、「空の参照」は実際に機能するため、「参照を空にすることはできません」という助言は、標準的なセッターによるセンセーショナルな形式主義としてあざけられます。「null参照」の例は次のとおりです。

int * a = NULL;
int&b = * a;

したがって、bにアクセスすると、プログラム例外が発生しました。

void f(intp)
{ 
    p = 0 ; 
} 
f(b);

もちろん、この問題を修正するための判断を加えることができます。

void f(intp)
{ 
    if(&p)p = 0 ; 
}

調子はいかがですか?しかし、それがポインタに置き換えられた場合、入力する文字数はまったく同じです。

void f(int * p)
{ 
    if(p)* p = 0 ; 
}

 したがって、「参照」を使用するか「ポインタ」を使用するかは、賢明な見方の問題だと思われます。

 

ただし、ただし。

 

これは本当に同じですか?

 

より複雑な例を見てみましょう:

// test.cpp 

#include <iostream> class A 
{ int a; 
}; クラスB 
{ int b; 
}; クラスC パブリック A、パブリックB 
{ int c; 
}; void fb(B&b)
{ 
    std :: cout <<&b << std :: endl; 
} void fb(B * b)
{ 
    std :: cout << b << std :: endl; 
} int main(int argc、char


    


    


    





* argv [])
{ 
    C * c = NULL; 

    fb(c); 

    fb( * c); 

    0を返し ます
}

コンパイルして実行すると、次のことがわかります。

$ ./ テスト
 0 
0x4

なぜ、&bが0でないのか、つまり「null参照」ではない理由です。現時点では、(&b)が役に立たない場合は、判断が追加されても同じです。

上記がLinux環境であることにお気づきかもしれませんが、Windows環境についてはどうでしょうか。

> test.exe
 00000000 
00000000

現時点では、「空の参照」は彼の「空」の属性を維持し、WindowsプラットフォームのC ++開発者のみがリラックスできます。

何が起こっていますか、あなたの目はあなたを欺いていますか?多分それはそうですが、CPUは私たちをだましません、私たちはアセンブリコードから本質を見ることができます。Linuxプラットフォームでコンパイルされたコードは次のとおりです。

関数メインのアセンブラコードのダンプ
0x0804870a <+ 0 >:push %ebp 
0x0804870b <+ 1 >:mov %esp、%ebp 
0x0804870d <+ 3 >:および$ 0xfffffff0、%esp 
0x08048710 <+ 6 >:sub $ 0x20 、%esp 
0x08048713 <+ 9 >:movl $ 0x0,0x1c(%esp)
0x0804871b <+ 17 >:cmpl $ 0x0,0x1c(%esp)
0x08048720 <+ 22 >:je 0x804872b <main + 33 > 
0x08048722 <+ 24 > :mov 0x1c(%esp)、%eax 
0x08048726 <+ 28 >:追加$ 0x4、%eax 
0x08048729 <+ 31 >:jmp 0x8048730 <main + 38 > 
0x0804872b <+ 33 >:mov $ 0x0、%eax 
0x08048730 <+ 38 >:mov %eax、(%esp)
0x08048733 <+ 41 >:コール0x80486df <FB(B *)> 
0x08048738 <+ 46 >:MOV 0x1cに(%ESP)、%eaxに
0x0804873c <+ 50 >:追加$ 0x4のを、%EAX 
0x0804873f <+ 53 >:MOV %EAX 、(%esp)
0x08048742 <+ 56>:コール0x80486b4 <fb(B&)> 
0x08048747 <+ 61 >:mov $ 0x0、%eax 
0x0804874c <+ 66 >:leave  
0x0804874d <+ 67 >:ret 

これはWindowsプラットフォーム用です。

wmain:
004114D0  プッシュEBP 
 004114D1  のMOV EBP、ESP 
 004114D3  サブESP、0DCh 
 004114D9の プッシュEBX 
 004114DAが プッシュESIは 
 004114DB  プッシュEDI 
 004114DC  LEA EDI、[EBP-0DCh] 
 004114E2  MOV ECX、37H 
 004114E7  のMOV EAX、0CCCCCCCCh 
 004114EC  担当者 STOS DWORD PTR ES:[edi] 
 004114EE  mov dword ptr [c]、0  
004114F5  mov eax、dword ptr [c] 
 004114F8  movdword ptr [rc]、eax 
 004114FB  cmp dword ptr [c]、0  
004114FF  je wmain + 3Fh(41150Fh) 
 00411501  mov eax、dword ptr [c] 
 00411504  add eax、4  
00411507  mov dword ptr [ebp-0DCh]、eax 
 0041150D  jmp wmain + 49h(411519h) 
 0041150F  mov dword ptr [ebp-0DCh]、0  
00411519  mov ecx、dword ptr [ebp-0DCh] 
 0041151F  push ecx 
 00411520  call fb(411118h) 
 00411525  add esp、4  
00411528 cmp dword ptr [rc]、0  
0041152C  je wmain + 6Ch(41153Ch) 
 0041152E  mov eax、dword ptr [rc] 
 00411531  add eax、4  
00411534  mov dword ptr [ebp-0DCh]、eax 
 0041153A  jmp wmain + 76h(411546h) 
 0041153C  mov dword ptr [ebp-0DCh]、0  
00411546  mov ecx、dword ptr [ebp-0DCh] 
 0041154C  push ecx 
 0041154D  call fb(41108Ch) 
 00411552  add esp、4  
00411555  xor eax、eax 
 00411557 pop edi 
 00411558  pop esi 
 00411559  pop ebx 
 0041155A  add esp、0DCh 
 00411560  cmp ebp、esp 
 00411562  call @ ILT + 345 (__RTC_CheckEsp)(41115Eh) 
 00411567  mov esp、ebp 
 00411569  pop ebp 
 0041156A  ret 

アセンブリコードは自分で勉強することに関心があるので、詳細には触れません。


振り返ってみると、2つのプラットフォームのコンパイラの2つの処理方法には妥当性があります。Windowsプラットフォームはフォールトトレランスを向上させ、Linuxプラットフォームは判断を減らし、参照を処理する際のパフォーマンスを向上させます。これは、WindowsとLinuxの異なる開発コンセプトを漠然と反映しています。

最後に、参照をnullにすることはできません。nullオブジェクトが存在する可能性がある場合は、ポインタを使用してください。


元のリンク:https : //blog.csdn.net/luansxx/article/details/10134139

おすすめ

転載: www.cnblogs.com/2018shawn/p/12724525.html