Motivo per passare un puntatore tramite riferimento in C ++?

In quali circostanze vorresti usare un codice di questa natura in c ++?

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

Si vorrebbe passare un puntatore per riferimento se si ha la necessità di modificare il puntatore piuttosto che l’object a cui punta il puntatore.

Questo è simile al perché vengono usati i doppi puntatori; l’utilizzo di un riferimento a un puntatore è leggermente più sicuro rispetto all’uso dei puntatori.

Il 50% dei programmatori C ++ amano impostare i puntatori su null dopo un’eliminazione:

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

Senza il riferimento, cambieresti solo una copia locale del puntatore, senza influenzare il chiamante.

La risposta di David è corretta, ma se è ancora un po ‘astratta, ecco due esempi:

  1. Potresti voler azzerare tutti i puntatori liberati per individuare i problemi di memoria in precedenza. C-style che dovresti fare:

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

    In C ++ per fare lo stesso, si potrebbe fare:

     template void freeAndZero(T* &ptr) { delete ptr; ptr = 0; } int* ptr = new int; ... freeAndZero(ptr); 
  2. Quando si ha a che fare con elenchi collegati, spesso semplicemente rappresentati come puntatori a un nodo successivo:

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

    In questo caso, quando si inserisce nell’elenco vuoto, è necessario modificare necessariamente il puntatore in entrata perché il risultato non è più il puntatore NULL . Questo è un caso in cui si modifica un puntatore esterno da una funzione, quindi avrebbe un riferimento al puntatore nella sua firma:

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

C’è un esempio in questa domanda .

Ho dovuto usare un codice come questo per fornire funzioni per allocare memoria a un puntatore passato e restituire le sue dimensioni perché la mia azienda “mi ha” obiettato usando l’STL

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

Non è bello, ma il puntatore deve essere passato per riferimento (o usare il doppio puntatore). In caso contrario, la memoria viene assegnata a una copia locale del puntatore se viene passata in base al valore che risulta in una perdita di memoria.

Un esempio è quando si scrive una funzione parser e si passa un puntatore sorgente da cui leggere, se si suppone che la funzione spinga quel puntatore in avanti dietro l’ultimo carattere che è stato correttamente riconosciuto dal parser. L’uso di un riferimento a un puntatore rende chiaro che la funzione sposterà il puntatore originale per aggiornare la sua posizione.

In generale, si utilizzano riferimenti a puntatori se si desidera passare un puntatore a una funzione e lasciare che il puntatore originale si sposti su un’altra posizione invece di spostarne semplicemente una copia senza influire sull’originale.

Un’altra situazione in cui potresti aver bisogno è se hai una collezione di puntatori e vuoi cambiarli usando l’algoritmo di stl. Esempio di for_each in c ++ 98.

 struct Storage { typedef std::list ObjectList; ObjectList objects; void change() { typedef void (*ChangeFunctionType)(Object*&); std::for_each (objects.begin(), objects.end(), &Storage::changeObject); } static void changeObject(Object*& item) { delete item; item = 0; if (someCondition) item = new Object(); } }; 

Altrimenti, se usi la firma changeObject (Oggetto * object) hai una copia del puntatore, non quella originale.