web-dev-qa-db-ja.com

C ++で参照によるポインターを渡す理由は?

どのような状況で、C++でこの種のコードを使用しますか?

void foo(type *&in) {...}

void fii() {
  type *choochoo;
  ...
  foo(choochoo);
}
86
Matthew Hoggan

ポインターが指しているオブジェクトではなく、ポインターを変更する必要がある場合は、参照によってポインターを渡します。

これは、ダブルポインターが使用される理由に似ています。ポインターへの参照を使用する方が、ポインターを使用するよりも若干安全です。

131
David Z.

C++プログラマの50%は、削除後にポインターをnullに設定することを好みます。

template<typename T>    
void moronic_delete(T*& p)
{
    delete p;
    p = nullptr;
}

参照がなければ、ポインタのローカルコピーを変更するだけで、呼び出し元には影響しません。

62
fredoverflow

デビッドの答えは正しいですが、それでもまだ少し抽象的な場合は、2つの例を示します。

  1. メモリの問題を早期に発見するために、すべての解放されたポインターをゼロにすることができます。行うCスタイル:

    void freeAndZero(void** ptr)
    {
        free(*ptr);
        *ptr = 0;
    }
    
    void* ptr = malloc(...);
    
    ...
    
    freeAndZero(&ptr);
    

    同じことをするC++では、次のようにすることができます。

    template<class T> void freeAndZero(T* &ptr)
    {
        delete ptr;
        ptr = 0;
    }
    
    int* ptr = new int;
    
    ...
    
    freeAndZero(ptr);
    
  2. リンクリストを扱う場合-多くの場合、次のノードへのポインタとして単に表されます:

    struct Node
    {
        value_t value;
        Node* next;
    };
    

    この場合、空のリストに挿入するときは、結果がNULLポインターではなくなるため、着信ポインターを必ず変更する必要があります。これは、関数から外部ポインターを変更する場合です。そのため、署名にポインターへの参照が含まれます。

    void insert(Node* &list)
    {
        ...
        if(!list) list = new Node(...);
        ...
    }
    

this question に例があります。

14
Antoine

私の会社はSTLを使用して「オブジェクト」であるため、渡されたポインターにメモリを割り当ててサイズを返す関数を提供するには、このようなコードを使用する必要がありました。

 int iSizeOfArray(int* &piArray) {
    piArray = new int[iNumberOfElements];
    ...
    return iNumberOfElements;
 }

ナイスではありませんが、ポインタは参照渡しする必要があります(またはダブルポインタを使用します)。そうでない場合、メモリリークが発生する値で渡される場合、メモリはポインタのローカルコピーに割り当てられます。

7

一例は、パーサーが正しく認識した最後の文字の後ろにそのポインターを前方にプッシュすることになっている場合に、パーサー関数を作成して読み取り元のソースポインターを渡す場合です。ポインターへの参照を使用すると、関数が元のポインターを移動してその位置を更新することが明確になります。

一般に、関数へのポインターを渡し、元に影響を与えずにそのコピーを移動するのではなく、originalポインターを他の位置に移動させたい場合は、ポインターへの参照を使用します。

2
BarbaraKwarc

これが必要になる可能性がある別の状況は、ポインタのstlコレクションがあり、stlアルゴリズムを使用してそれらを変更する場合です。 C++ 98のfor_eachの例。

struct Storage {
  typedef std::list<Object*> ObjectList;
  ObjectList objects;

  void change() {
    typedef void (*ChangeFunctionType)(Object*&);
    std::for_each<ObjectList::iterator, ChangeFunctionType>
                 (objects.begin(), objects.end(), &Storage::changeObject);
  }

  static void changeObject(Object*& item) {
    delete item;
    item = 0;
    if (someCondition) item = new Object();
  } 

};

それ以外の場合、使用する場合 changeObject(Object * item) 署名にはポインタのコピーがあり、元のコピーではありません。

0
Nine