2012-04-20 8 views
70

¿Bajo qué circunstancias le gustaría usar código de esta naturaleza en C++?Motivo para pasar un puntero por referencia en C++?

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

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

si necesita devolver un puntero - mejor use un valor de retorno – littleadv

+5

¿Puede explicar por qué? Este comentario no es muy útil. Mi pregunta es bastante legítima. Esto se está utilizando actualmente en el código de producción. Simplemente no entiendo completamente por qué. –

+1

David lo resume bastante bien. El puntero en sí está siendo modificado. – chris

Respuesta

111

Usted quiere pasar un puntero de referencia si usted tiene una necesidad de modificar el puntero en lugar del objeto que el puntero está apuntando.

Esto es similar a por qué se utilizan punteros dobles; usar una referencia a un puntero es ligeramente más seguro que usar punteros.

+11

¿Tan similar a un puntero de un puntero, excepto un nivel menos de indirección para la semántica de paso por referencia? –

+1

Eso es precisamente :) :) –

+0

Me gustaría agregar que a veces también desea devolver un puntero por referencia. Por ejemplo, si tiene una clase que contiene datos en una matriz asignada dinámicamente, pero desea proporcionar acceso (no constante) a estos datos para el cliente. Al mismo tiempo, no desea que el cliente pueda manipular la memoria a través del puntero. –

7

he tenido que usar un código como éste para proporcionar funciones para asignar memoria a un puntero pasado y volver a su tamaño, ya que mi empresa "objeto" a mí usando el TEL

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

No es agradable, pero el puntero debe pasarse por referencia (o usar doble puntero). De lo contrario, la memoria se asigna a una copia local del puntero si se pasa por un valor que da como resultado una pérdida de memoria.

0

Otra situación en la que puede necesitar esto es si tiene stl colección de punteros y quiere cambiar utilizando el algoritmo STL. Ejemplo de for_each en C++ 98.

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(); 
    } 

}; 

De lo contrario, si se utiliza changeObject (* Objeto artículo) firma que tiene copia del puntero, no original.

14

respuesta de David es correcta, pero si aún así es un poco abstracto, aquí hay dos ejemplos:

  1. Es posible que desee poner a cero todos los punteros liberados para detectar los problemas de memoria anterior. C-estilo que haría:

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

    En C++ para hacer lo mismo, es posible hacer:

    template<class T> void freeAndZero(T* &ptr) 
    { 
        delete ptr; 
        ptr = 0; 
    } 
    
    int* ptr = new int; 
    
    ... 
    
    freeAndZero(ptr); 
    
  2. Cuando se trata de listas enlazadas - representados a menudo simplemente como punteros a un nodo siguiente :

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

    En este caso, cuando se inserta en la lista vacía que necesariamente debe cambiar el puntero de entrada porque el resultado no es el puntero NULL más. Este es un caso en el que se modifica un puntero externo de una función, por lo que tendría una referencia a puntero en su firma:

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

Hay un ejemplo en this question.

50

50% de los programadores de C++ como para fijar sus punteros a NULL después de una eliminación:

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

Sin la referencia, sólo se estaría cambiando una copia local del puntero, que no afectan a la persona que llama.

+15

Me gusta el nombre;) – 4pie0

+2

Este ejemplo lo dejó claro. Para entender. –

+0

Cambiaré el sonido estúpido para encontrar la respuesta: ¿por qué se llama eliminación morónica? ¿Qué me estoy perdiendo? – Sammaron

0

Un ejemplo es cuando escribe una función de analizador y le pasa un puntero de origen para leer, si se supone que la función debe empujar ese puntero hacia adelante detrás del último carácter que ha sido reconocido correctamente por el analizador.El uso de una referencia a un puntero deja claro entonces que la función moverá el puntero original para actualizar su posición.

En general, se utilizan referencias a punteros si quieres pasar un puntero a una función y que se mueva que originales puntero a alguna otra posición en lugar de sólo mover una copia del mismo sin afectar el original.

+0

¿Por qué el voto a favor? ¿Hay algo mal con lo que escribí? ¿Le importaria explicar? :PAG – BarbaraKwarc

Cuestiones relacionadas