質問

C ++で参照渡しよりもポインタ渡しの利点は何ですか?

最近、参照で渡すのではなく、ポインタで関数の引数を渡すことを選択したいくつかの例を見てきました。これを行う利点はありますか?

例:

func(SPRITE *x);

の呼び出しで

func(&mySprite);

vs。

func(SPRITE &x);

の呼び出しで

func(mySprite);
役に立ちましたか?

解決

ポインターはNULLパラメーターを受け取ることができますが、参照パラメーターは受け取ることができません。 「オブジェクトなし」を渡したい場合は、参照の代わりにポインターを使用してください。

また、ポインタで渡すことにより、オブジェクトが値渡しであるか参照渡しであるかを呼び出しサイトで明示的に確認できます:

// Is mySprite passed by value or by reference?  You can't tell 
// without looking at the definition of func()
func(mySprite);

// func2 passes "by pointer" - no need to look up function definition
func2(&mySprite);

他のヒント

ポインターによる受け渡し

  • 発信者は住所を取得する必要があります->透明ではない
  • 0の値は、 nothing を意味するために提供できます。これは、オプションの引数を提供するために使用できます。

参照渡し

  • 呼び出し元はオブジェクトを渡すだけです->トランスペアレント。ポインター型のオーバーロードは不可能であるため、オペレーターのオーバーロードに使用する必要があります(ポインターは組み込み型です)。したがって、ポインターを使用して string s =& str1 +& str2; を実行することはできません。
  • 0の値は使用できません->呼び出された関数はそれらをチェックする必要はありません
  • constへの参照は一時的なものも受け入れます。 void f(const T& t); ... f(T(a、b、c)); 、テンポラリのアドレスを取得できないため、ポインタをそのように使用することはできません。
  • 最後になりましたが、参照は使いやすいです->バグの可能性が少なくなります。

アレン・ホルブの「足で自分を撃つには十分なロープ」次の2つのルールをリストします。

120. Reference arguments should always be `const`
121. Never use references as outputs, use pointers

彼は、参照がC ++に追加されたいくつかの理由をリストしています:

  • これらはコピーコンストラクタを定義するために必要です
  • これらは演算子のオーバーロードに必要です
  • const 参照により、コピーを回避しながら値渡しのセマンティクスを使用できます

主な点は、参照が「出力」パラメーターとして使用されるべきではないということです。呼び出しサイトでは、パラメーターが参照パラメーターであるか値パラメーターであるかが示されないためです。したがって、彼のルールは、引数として const 参照のみを使用することです。

個人的には、パラメータが出力パラメータであるかどうかをより明確にするため、これは良い経験則だと思います。ただし、個人的にはこれに全般的に同意しますが、出力パラメーターを参照として主張する場合、チームの他のユーザーの意見に左右されることを許可します(一部の開発者は非常に気に入っています)。

" cplusplus.com:"の記事による推論が好きです

  
      
  1. 関数がパラメーターを変更する必要がなく、値をコピーしやすい場合(int、double、char、boolなど...単純型。std:: string、std ::ベクトル、および他のすべてのSTLコンテナは単純型ではありません。)

  2.   
  3. 値のコピーに時間がかかり、かつ関数がAND NULLを指す値を変更したくない場合はconstポインターで渡す。関数が処理する有効な期待値です。

  4.   
  5. 値のコピーが高価で、かつ関数がNULLを指す値を変更したい場合、非constポインターで渡す。また、関数が処理する有効な期待値です。

  6.   
  7. 値のコピーに時間がかかり、関数が参照される値を変更したくない場合、const参照で渡すANDポインターが代わりに使用された場合、NULLは有効な値ではありません。

  8.   
  9. 値のコピーにコストがかかり、かつ参照される値を変更する関数が必要な場合、非連続参照で渡すANDポインターが代わりに使用された場合、NULLは有効な値ではありません。

  10.   
  11. テンプレート関数を記述するとき、この議論の範囲外であると考えるいくつかのトレードオフがあるため、明確な答えはありませんが、ほとんどのテンプレート関数はパラメータを受け取ると言うだけで十分ですただし、反復子の構文はポインターの構文(" dereference"へのアスタリスク)に類似しているため、イテレーターを引数として予期するテンプレート関数もデフォルトでポインターを受け入れます(そして、 NULLイテレータの概念の構文は異なります)。

  12.   
     

http://www.cplusplus.com/articles/z6vU7k9E/

これから私が理解したことは、ポインターまたは参照パラメーターを使用することを選択することの主な違いは、NULLが許容値であるかどうかです。それだけです。

値が入力、出力、変更可能などであるかどうかは、結局、関数に関するドキュメント/コメントにあるべきです。

前述の投稿の説明:


参照は、null以外のポインターを取得することを保証するではありません。 (多くの場合、そのように扱います。)

恐ろしく悪いコードですが、woodshed bad コードの背後にあるように、次のコードは&をコンパイルします。実行:(少なくとも私のコンパイラの下で。)

bool test( int & a)
{
  return (&a) == (int *) NULL;
}

int
main()
{
  int * i = (int *)NULL;
  cout << ( test(*i) ) << endl;
};

参照に関する実際の問題は、コンストラクターで割り当て、デストラクタで割り当て解除を行う IDIOTS と呼ばれる他のプログラマーにあります。 コピーコンストラクタまたはoperator =()の指定に失敗します。

突然、 foo(BAR bar) foo(BAR &amp; bar)には違いがあります。 (自動ビット単位コピー操作が呼び出されます。デストラクタの割り当て解除は2回呼び出されます。)

ありがたいことに、最新のコンパイラは同じポインタのこの二重の割り当て解除を選択します。 15年前はそうではありませんでした。 (gcc / g ++では、 setenv MALLOC_CHECK_ 0 を使用して古い方法を再確認します。)DEC UNIXの場合、2つの異なるオブジェクトに割り当てられた同じメモリ内で発生します。デバッグの楽しみがたくさんあります...


より実際的に:

  • 参照は、他の場所に保存されているデータを変更していることを隠します。
  • 参照とコピーされたオブジェクトを混同するのは簡単です。
  • ポインターはそれを明らかにします!

そうでもない。内部的には、参照渡しは基本的に参照オブジェクトのアドレスを渡すことで実行されます。したがって、ポインターを渡すことによる効率の向上は実際にはありません。

ただし、参照渡しには1つの利点があります。渡されるオブジェクト/タイプのインスタンスを持つことが保証されます。ポインターを渡すと、NULLポインターを受け取るリスクが発生します。参照渡しを使用すると、暗黙的なNULLチェックを1レベル上に関数の呼び出し元にプッシュすることになります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top