web-dev-qa-db-ja.com

ポインターと参照

関数に使用する元の変数を与えるときのより良い方法は次のとおりです。

unsigned long x = 4;

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

または:

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

IOW:他のものを選ぶ理由はありますか?

247
Jack Reza

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

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

それ以外の場合は参照を使用します。

275

次の関数呼び出しコーディングガイドラインを確立することで、あなたは本当に恩恵を受けると思います。

  1. 他のすべての場所と同様に、常にconst-- correctにしてください。

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

    • 理由1:呼び出し元として、must beで渡すものはすべて使用可能な状態であることがわかります。

    • 理論的根拠2:calledとして、あなたはisが使用可能な状態にあることを知っています。したがって、その値に対してNULLチェックやエラー処理を行う必要はありません。

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

  3. 関数の引数がout-valueである場合、参照で渡します。

    • 理由:アイテム2を壊したくない...
  4. 値がPOD( Plain old Datastructure )または十分に小さい(メモリ単位)または他の方法で十分に安い(時間単位)の場合にのみ、「const参照によるパス」よりも「値によるパス」を選択します。 ) コピーする。

    • 根拠:不要なコピーを避けてください。
    • 注:十分に小さいおよび十分に安いは絶対的な測定値ではありません。
71
Johann Gerell

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

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

24
Aaron N. Tubbs

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

7
Max Caceres

値がないことを示す必要があるパラメーターがある場合、パラメーターをポインター値にして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);
}
5
Kiley Hykawy

ポインタ

  • ポインターは、メモリアドレスを保持する変数です。
  • ポインター宣言は、基本型、*、および変数名で構成されます。
  • ポインターは、存続期間中に任意の数の変数を指すことができます
  • 現在、有効なメモリ位置を指し示していないポインターには、値nullが与えられます(これはゼロです)

    BaseType* ptrBaseType;
    BaseType objBaseType;
    ptrBaseType = &objBaseType;
    
  • &は、オペランドのメモリアドレスを返す単項演算子です。

  • 間接参照演算子(*)は、ポインターが指す変数に格納されている値にアクセスするために使用されます。

       int nVar = 7;
       int* ptrVar = &nVar;
       int nVar2 = *ptrVar;
    

参照

  • 参照(&)は、既存の変数のエイリアスのようなものです。

  • 参照(&)は、自動的に逆参照される定数ポインターのようなものです。

  • 通常、関数の引数リストと関数の戻り値に使用されます。

  • 参照は作成時に初期化する必要があります。

  • 参照がオブジェクトに初期化されると、別のオブジェクトを参照するように変更することはできません。

  • NULL参照を持つことはできません。

  • Const参照はconst intを参照できます。 constの値を持つ一時変数で行われます

    int i = 3;    //integer declaration
    int * pi = &i;    //pi points to the integer i
    int& ri = i;    //ri is refers to integer i – creation of reference and initialization
    

enter image description here

enter image description here

4
Saurabh Raoot

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

4
RezaPlusPlus

C#のoutキーワードを検討してください。コンパイラーは、メソッドの呼び出し元がoutキーワードをout引数に適用することを要求します(out引数が既にある場合は知っていますが)。これは読みやすさを高めることを目的としています。最近のIDEでは、これは構文(またはセマンティック)強調表示の仕事だと思う傾向があります。

3

ポインター:

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

参照:

  • Nullにすることはできません。
  • バインドされると、変更できません。
  • 呼び出し元は、&を明示的に使用する必要はありません。パラメーターが変更されているかどうかを確認するには、関数の実装に移動する必要があるため、これは時々悪いと見なされます。
2
Germán Diago

渡すコンテンツを変更/保持したい理由がない限り、const参照で渡します。

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

変更したくない各パラメーターでconstを使用することを確認してください。これは、関数で愚かなことを行うことを防ぐだけでなく、渡された値に対して関数が何をするかを適切に示します。これには、指すものだけを変更したい場合にポインターconstを作成することが含まれます.

2
NotJarvis

参照はポインターに似ていますが、参照によって参照される値にアクセスするためにプレフィックス∗を使用する必要がない点が異なります。また、初期化後に別のオブジェクトを参照する参照を作成することはできません。

参照は、関数の引数を指定するのに特に役立ちます。

詳細については、「Bjarne Stroustrup」による「C++のツアー」(2014)11〜12ページを参照してください。

0
amirfg