270

関数に元の変数を指定して操作する場合のより良い方法は次のとおりです。

unsigned long x = 4;

void func1(unsigned long& val) {
     val = 5;            
}
func1(x);

また:

void func2(unsigned long* val) {
     *val = 5;
}
func2(&x);

IOW:どちらかを選ぶ理由はありますか?

4

12 に答える 12

296

私の経験則は次のとおりです。

ポインターを使用してポインター演算を実行する場合(たとえば、配列をステップスルーするためにポインターアドレスをインクリメントする場合)、またはNULLポインターを渡す必要がある場合は、ポインターを使用します。

それ以外の場合は参照を使用してください。

于 2008-09-22T10:40:15.977 に答える
74

次の関数呼び出しのコーディング ガイドラインを確立することでメリットが得られると思います。

  1. 他のすべての場所と同様に、常にconst正確であること。

    • 注: これは特に、out-values (項目 3 を参照) と値によって渡される値 (項目 4 を参照) のみがconst指定子を欠いている可能性があることを意味します。
  2. 値 0/NULL が現在のコンテキストで有効な入力である場合にのみ、ポインターによって値を渡します。

    • 根拠 1: caller として、渡すものはすべて使用可能な状態でなければならないことがわかります。

    • 根拠 2:と呼ばれるように、入ってくるもの何でも使用可能な状態にあることがわかっています。したがって、その値に対して NULL チェックやエラー処理を行う必要はありません。

    • 根拠 3: 根拠 1 と 2 はコンパイラによって強制されます。可能であれば、コンパイル時に常にエラーをキャッチしてください。

  3. 関数の引数が out-value の場合は、参照によって渡します。

    • 理由: 項目 2 を壊したくありません...
  4. 値が POD ( Plain old Datastructure ) であるか、十分に小さい (メモリの観点から) 場合、または他の方法で (時間の観点から) コピーするのに十分安価な場合にのみ、[const 参照による受け渡し] ではなく [値による受け渡し] を選択します。

    • 根拠: 不要なコピーを避ける。
    • 注:十分に小さくて十分安いということは、絶対的な測定可能値ではありません。
于 2008-09-22T11:37:17.337 に答える
24

これは最終的には主観的なものになります。ここまでの議論は役に立ちますが、これに対する正しい答えや決定的な答えはないと思います。多くは、スタイルのガイドラインとその時点でのニーズによって異なります。

ポインターにはいくつかの異なる機能 (何かを NULL にすることができるかどうか) がありますが、出力パラメーターの実際の最大の違いは純粋に構文です。たとえば、Google の C++ スタイル ガイド ( https://google.github.io/styleguide/cppguide.html#Reference_Arguments ) は、出力パラメーターのポインターのみを義務付け、const である参照のみを許可します。その理由は読みやすさの 1 つです。値の構文を持つものには、ポインターのセマンティックな意味があってはなりません。これが必ずしも正しいか間違っているかを示唆しているわけではありませんが、ここでのポイントは、正確さではなく、スタイルの問題だということだと思います.

于 2008-09-22T13:11:31.400 に答える
7

変数の値を変更する場合は、ポインターを渡す必要があります。技術的には参照またはポインターを渡すことは同じですが、ユースケースでポインターを渡すと、関数によって値が変更されるという事実が「アドバタイズ」されるため、より読みやすくなります。

于 2008-09-22T15:28:12.210 に答える
5

値が存在しないことを示す必要があるパラメーターがある場合は、パラメーターをポインター値にして NULL を渡すのが一般的です。

ほとんどの場合 (安全性の観点から) より良い解決策は、boost::optionalを使用することです。これにより、オプションの値を参照によって渡すことも、戻り値として渡すこともできます。

// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& optional_str)
{
    if (optional_str)
    {
       cout << *optional_str << std::endl;
    }
    else
    {
       cout << "(no string)" << std::endl;
    }
}

// Sample method using optional as return value
boost::optional<int> ReturnOptional(bool return_nothing)
{
    if (return_nothing)
    {
       return boost::optional<int>();
    }

    return boost::optional<int>(42);
}
于 2008-10-17T21:53:19.640 に答える
5

可能な場合は参照を使用し、必要な場合はポインターを使用します。C++ の FAQから: 「いつ参照を使用する必要があり、いつポインターを使用する必要がありますか?」

于 2011-03-01T18:59:47.783 に答える
3

C#のoutキーワードを考えてみましょう。コンパイラーは、メソッドの呼び出し元がoutキーワードをout argsに適用する必要がありますが、それらが既に認識されている場合でも同様です。これは、読みやすさを向上させることを目的としています。最近のIDEでは、これは構文(またはセマンティック)の強調表示の仕事だと思う傾向があります。

于 2008-10-17T22:22:19.550 に答える
3

参照は暗黙のポインターです。基本的に、参照が指す値を変更できますが、参照を別のものに変更することはできません。したがって、私の 2 セントは、パラメーターの値を変更するだけの場合は参照として渡しますが、パラメーターを変更して別のオブジェクトを指すようにする必要がある場合は、ポインターを使用して渡します。

于 2008-09-22T15:23:53.097 に答える
2

ポインター:

  • を割り当てることができますnullptr(またはNULL)。
  • 呼び出しサイトでは&、型がポインター自体ではない場合に使用する必要があり、オブジェクトを変更していることを明示的にします。
  • ポインターはリバウンドできます。

参考文献:

  • null にすることはできません。
  • 一度バインドすると、変更できません。
  • 呼び出し元は明示的に を使用する必要はありません&。パラメータが変更されているかどうかを確認するには、関数の実装に移動する必要があるため、これは時々悪いと見なされます。
于 2013-10-29T13:09:06.943 に答える
2

渡す内容を変更/保持する理由がない限り、const 参照で渡します。

ほとんどの場合、これが最も効率的な方法です。

変更したくない各パラメーターで必ず const を使用してください。これにより、関数内で愚かなことをするのを防ぐだけでなく、関数が渡された値に対して何をするかを他のユーザーに示すことができます。これには、指している内容のみを変更したい場合にポインター const を作成することが含まれます...

于 2008-09-22T11:43:55.497 に答える