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


97

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

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

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

ポインタを返す必要がある場合
勧めし

6
理由を説明できますか?この表彰はあまり役に立ちません。私の質問はかなり正当です。これは現在、量産コードで使用されています。理由がよくわかりません。
マシューホガン2012

1
デビッドはそれをかなりうまくまとめています。ポインタ自体が変更されています。
クリス

2
関数で「新規」演算子を呼び出す場合は、この方法を渡します。
NDEthos 2014年

回答:


142

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

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


14
ポインタのポインタに似ていますが、参照渡しセマンティクスの間接参照のレベルが1つ少ない点が異なります。

また、参照によってポインタを返す必要がある場合があることを付け加えておきます。たとえば、動的に割り当てられた配列にデータを保持するクラスがあるが、このデータへの(一定でない)アクセスをクライアントに提供したい場合。同時に、クライアントがポインタを介してメモリを操作できないようにする必要があります。

2
@ウィリアム、詳しく説明できますか?それは面白そう。それは、そのクラスのユーザーが内部データバッファーへのポインターを取得して読み書きできることを意味しますが、たとえば、そのバッファーを解放しdeleteたり、そのポインターをメモリ内の他の場所に再バインドしたりすることはできませんか?それとも私はそれを間違っていましたか?
BarbaraKwarc

2
@BarbaraKwarcもちろん。動的配列の単純な実装があるとします。当然、あなたは[]演算子をオーバーロードするでしょう。これに対する可能な(そして実際には自然な)署名の1つはですconst T &operator[](size_t index) const。しかし、あなたも持つことができますT &operator[](size_t index)。あなたは同時に両方を持つことができます。後者では、次のようなことができますmyArray[jj] = 42。同時に、データへのポインタを提供していないため、呼び出し元はメモリを乱用することはできません(たとえば、誤って削除してしまうなど)。

ああ。私はあなたがポインタへの参照を返すことについて話していると思ったバッファ自体の操作を許可せずに(たとえば、バッファを解放することなく)、バッファへの読み取り/書き込みアクセス権を与える。単純な古い参照を返すことは別のものであり、私はそれを知っています。
BarbaraKwarc

65

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

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

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


19
私は名前が好きです。)
4pie0

2
私は答えを理解するために愚かなサウンドを交換します:なぜそれはmoronic削除と呼ばれるのですか?何が欠けていますか?
Sammaron、2015

1
@Sammaron履歴を見ると、以前は関数テンプレートが呼び出されてparanoid_deleteいましたが、パピーはその名前をに変更しましたmoronic_delete。彼はおそらく他の50%に属しています;)とにかく、後のnullへのポインターの設定deleteはほとんど役に立ちません(とにかくスコープ外に出る必要があるため)、「解放後の使用」バグの検出を妨げることが多いです。
fredoverflow、2015

@fredoverflow私はあなたの応答を理解していますが、@ Puppy deleteは一般的に愚かだと思っているようです。子犬、私はいくつかグーグルをしました、なぜ削除が完全に役に立たないのかわかりません(多分私も恐ろしいグーグルです;))。もう少し説明したり、リンクを提供したりできますか?
Sammaron、2015

@ Sammaron、C ++には「スマートポインター」があり、通常のポインターをカプセル化し、スコープから外れたときに自動的に「削除」を呼び出します。スマートポインターは、この問題を完全に排除するため、Cスタイルのダムポインターよりもはるかに推奨されます。
tjwrona1992

14

デビッドの答えは正しいですが、それでもまだ抽象的な場合は、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(...);
        ...
    }

この質問には例があります。


8

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

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

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


2

たとえば、パーサーが正しく認識した最後の文字の後ろにポインターを押し込むことが想定されている場合に、パーサー関数を記述してそこにソースポインターを渡します。ポインターへの参照を使用すると、関数が元のポインターを移動してその位置を更新することが明確になります。

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


なぜ反対票か。私が書いたものに何か問題がありますか?説明してもいいですか?:P
BarbaraKwarc 2017年

0

これが必要になる別の状況は、ポインタの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)シグネチャを使用すると、元のポインタではなく、ポインタのコピーが得られます。


これは「変更オブジェクト」ではなく「置換オブジェクト」です-違いがあります
serup '25年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.