9

私は C++ FAQ を読んでいました - 「8.6 - When should I use references, and when should I use pointers?」 特にこのステートメント:

可能な場合は参照を使用し、必要な場合はポインターを使用します。

...

上記の例外は、関数のパラメーターまたは戻り値が「センチネル」参照 (オブジェクトを参照しない参照) を必要とする場合です。これは通常、ポインターを返す/取得し、NULL ポインターにこの特別な意味を与えることによって行うのが最善です (参照は、逆参照された NULL ポインターではなく、常にオブジェクトをエイリアスする必要があります)。

私が見てきたことから、「センチネル」参照の必要性は、参照の代わりにポインターを使用する理由であることがよくあります。私が疑問に思っているのは、なぜC++には参照用の特別な「NULL値」がないのですか? ポインターがほとんど不要になり、多くの問題が解決されるようです。

では、なぜそれが言語仕様の一部ではなかったのでしょうか?

編集:

私の質問が明確かどうかはわかりません.NULL参照について文字通り質問しているのではありません。ほとんどの場合、C++ では「参照はオブジェクトです」と読みます。また、ほとんどの OOP 言語では、オブジェクトを NULL にすることができます - Pascal、C#、Java、JavaScript、PHPsomeObject = nullなどsomeObject := nil。実際、Pascal はポインターもサポートしていますがnil、使用法があるため、オブジェクトを にすることもできます。では、なぜ C++ はどこか特殊で、NULL オブジェクトを持たないのでしょうか? それは単なる見落としでしたか、それとも実際の決定でしたか?

4

5 に答える 5

14

参照は、変更されることのない有効なメモリ アドレスを指しているという意味を持っているためです。つまり、逆参照は安全/定義済みであるため、NULL チェックは必要ありません。設計上、参照を再割り当てすることはできません。

var が NULL になる可能性があり、クライアント コードでそのケースを処理する必要がある場合は、ポインターを使用します。有効な/初期化されたメモリアドレスを保証できる場合は、参照を使用します。

ポインターを使用する 1 つの例は、クラスのメンバーとして、クラスの構築時に不明または初期化できないインスタンスへの「参照」を格納することです。ただし、メンバー参照は構築時に (初期化子リストを介して) 初期化する必要があり、その割り当てを延期することはできません。

null 参照を許可すると、構文以外のポインターと同じになります (同じ NULL チェックを行う必要があります)。

アップデート:

「そして、ほとんどの OOP 言語では、オブジェクトを NULL にすることができます - Pascal、C#、Java、JavaScript、PHP など。[...] では、なぜ C++ は何らかの形で特別であり、NULL オブジェクトを持たないのですか?それは単なる見落としでしたか?それとも実際の決定?」

あなたはこれについて少し混乱していると思います。Java や C# などは「NULL オブジェクト」の印象を与えるかもしれませんが、これらのオブジェクト参照は多かれ少なかれ C++ ポインターに似ており、より単純な構文、GC インスツルメンテーション、および例外スローを備えています。これらの言語では、「Null オブジェクト」を操作すると、 NullReferenceException (C#)のような何らかの例外が発生します。地獄、Java ではNullPointerExceptionと呼ばれます。

null安全に使用する前に確認する必要があります。C++ ポインターのようなものです (ただし、ほとんどのマネージ言語ではポインターはデフォルトで NULL に初期化されますが、C++ では通常、初期ポインター値の設定はユーザー次第です (それ以外の場合は未定義/既に存在するメモリは何でも))。

C++ の見解は、選択肢を持つことに関するものであり、したがって冗長です。

  • 単純なポインターを使用して、必要に応じて NULL をチェックして、好きなようにします。
  • コンパイラが強制する有効性セマンティック/制約を持つ参照を使用します。
  • 簿記を行い、好きなように動作する独自のスマートポインターをロールバックします。
  • void ポインターを (慎重に!) 使用して、必要に応じて型指定されていないメモリ ブロックを参照します。
于 2012-07-10T07:55:41.057 に答える
6

ポインターと参照の違いを見てください。標準では参照の実装方法は公開されていますが、現時点では常にポインターとして実装されています。

つまり、それらの主な違いは、a) セマンティクス、b) ポインターを再配置できる、c) ポインターを null にできる、ということです。

簡単に言えば、これは意図的に行われたということです。プログラマーとして参照を参照する場合、a) その参照は入力されている b) 変更されない (c) オブジェクトと同じセマンティクスで使用できる) ことを知っておく必要があります。

標準で null 参照が許可されている場合、参照を使用する前に常に null をチェックする必要がありますが、これは望ましくありません。

編集:

あなたの編集に関して、ここでの混乱は、最も単純な OO 言語が何が起こっているのかを隠しているという事実に起因する可能性があると思います。Javaを例にとると、NULLオブジェクトがあり、それらを割り当てることができるように見えますが、実際にはできません-実際に起こっているのは、Javaにはポインターしかなく、それらのポインターにnull値を割り当てることができるということです. 実際に Java でオブジェクトを直接持つことは不可能であるため、ポインターのセマンティクスを廃止し、ポインターをオブジェクトとして扱います。C++ は単により強力であり、エラーが発生しやすい (Java 愛好家は、スタック ユーザー クラス インスタンスは必要ないと言うでしょう。Java にそれらを持たないという決定は、複雑さを軽減し、Java を使いやすくするために推進されました)。また、Java にはオブジェクトがないため、参照もありません。しかし、実際には役に立たないものは、

于 2012-07-10T07:58:48.837 に答える
1

C ++参照は、他のほとんどの言語がこの用語を使用しているという意味での参照ではありません。エイリアスのようなものです。C ++参照を使用する場合、ポインターを逆参照するのと同じように「逆参照」する必要はありません。それは事実上それに割り当てられたオブジェクトです。

nullオブジェクトインスタンスのようなものは実際にはないので、そのようなものへのC++参照を作成することはできません。他の言語では、null参照はC++のnullポインターと同等です。実際には何も含まれていません。

さて、あなたの他の考えに関して:1.null不可の参照を持つことは私の心にとって良いことです。つまり、すべての場所でnullをチェックする必要がなく、参照によって渡すことのすべての利点を得ることができます。2. null許容参照はポインタを置き換えません...低レベルでメモリまたはIO作業を行う必要がある場合は、メモリおよびメモリマップドデバイスへのrawアクセスが必要になります。まさにこの理由で、管理された参照と管理されていないポインターを持つC#(またはC ++ / CLR)を見ることができます。

于 2012-07-10T10:14:32.477 に答える
1

定義による参照は、別の変数またはオブジェクトに関連付ける必要があります。したがって、空または null 参照の種類は、その存在目的に違反します。

技術的には、ヌル参照から始めて、それを変数に割り当てるか、後で別の変数に再割り当てすることを意味します。これは、参照が作成されることを意図したものではありません。

参照が単純に複製できないポインターの使用法が他にもいくつかあります。たとえば、ポインタを使用して少量のメモリで複雑なデータ (バイトのシーケンス) の大きなチャンクを参照し、ポインタに 8 バイト程度しか費やさずに、必要なだけ頻繁にそれを渡します。同等のメモリを浪費せずに参照を使用してそれを行うことはできません。

参照は常に型に関連付けられますが、ポインターの場合はそうではありません。

于 2012-07-10T07:58:03.007 に答える
0

参照は何かを参照する必要があるため、null 参照は使用できません。
Cには参照がなく、この言語ではポインターしか使用できないため、これはC言語との互換性があります

于 2012-07-10T07:55:26.200 に答える