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);
nothing
を意味する0の値を提供できます。これは、オプションの引数を提供するために使用できます。string s = &str1 + &str2;
を実行することはできません。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」の記事による推論が好きです。
関数がパラメーターを変更することを望まず、値のコピーが簡単な場合(int、double、char、boolなど...単純型。std:: string、std :: vector、および他のすべてのSTLコンテナは単純なタイプではありません。)
値のコピーに時間がかかり、かつ関数がAND NULLを指す値を変更したくない場合、constポインターを渡します。これは、関数が処理する有効な期待値です。
値のコピーに時間がかかり、かつ関数がAND NULLを指す値を変更したい場合は、非定数ポインターを渡します。これは、関数が処理する有効な期待値です。
値のコピーに時間がかかり、関数が参照される値を変更したくない場合、const参照を渡します。ポインタが代わりに使用された場合、NULLは有効な値ではありません。
値のコピーに時間がかかり、関数が参照する値を変更する場合、非連続参照を渡します。ポインタが代わりに使用された場合、NULLは有効な値ではありません。
テンプレート関数を作成する場合、この議論の範囲外であると考えるいくつかのトレードオフがあるため、明確な答えはありませんが、ほとんどのテンプレート関数は値または(定数)参照によってパラメータを取ると言えば十分ですただし、イテレータの構文はポインタの構文(「参照解除」へのアスタリスク)に類似しているため、イテレータを引数として期待するテンプレート関数もデフォルトでポインタを受け入れます(NULLイテレータの概念には異なる構文があるため、NULLをチェックしません) )。
これから私が取るのは、ポインターまたは参照パラメーターを使用することを選択することの主な違いは、NULLが許容値であるかどうかです。それでおしまい。
値が入力、出力、変更可能などであるかどうかは、結局、関数に関するドキュメント/コメントにあるべきです。
上記の投稿の説明:
参照はではなく null以外のポインターを取得することを保証します。 (多くの場合、それらをそのように扱います。)
恐ろしく悪いコードですが、woodshedbadコードの背後に連れて行って、次のコードをコンパイルして実行します:(少なくとも私のコンパイラの下では)
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 &の間に世界の違いがあります=バー)。 (自動ビット単位コピー操作が呼び出されます。デストラクタの割り当て解除は2回呼び出されます。)
ありがたいことに、最新のコンパイラは、同じポインタのこの二重の割り当て解除を選択します。 15年前はそうではありませんでした。 (gcc/g ++では、setenv MALLOC_CHECK_ 0を使用して古い方法を再検討します。)DEC UNIXでは、同じメモリが2つの異なるメモリに割り当てられます。オブジェクト。デバッグがたくさんあります...
より実際的に:
あんまり。内部的には、参照渡しは基本的に参照オブジェクトのアドレスを渡すことで実行されます。そのため、ポインターを渡すことによる効率の向上は実際にはありません。
ただし、参照渡しには1つの利点があります。渡されるオブジェクト/タイプのインスタンスを持つことが保証されます。ポインターを渡すと、NULLポインターを受け取るリスクが発生します。参照渡しを使用すると、暗黙的なNULLチェックを1レベル上に関数の呼び出し元にプッシュできます。