Pregunta

¿En qué circunstancias podría querer utilizar dirección indirecta múltiple (es decir, una cadena de punteros como en Foo **) en C++?

¿Fue útil?

Solución

El uso más común, como señaló @aku, es permitir que un cambio en un parámetro de puntero sea visible después de que regrese la función.

#include <iostream>

using namespace std;

struct Foo {
    int a;
};

void CreateFoo(Foo** p) {
    *p = new Foo();
    (*p)->a = 12;
}

int main(int argc, char* argv[])
{
    Foo* p = NULL;
    CreateFoo(&p);
    cout << p->a << endl;
    delete p;
    return 0;
}

Esto se imprimirá

12

Pero existen otros usos útiles, como en el siguiente ejemplo, para iterar una matriz de cadenas e imprimirlas en la salida estándar.

#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
    const char* words[] = { "first", "second", NULL };
    for (const char** p = words; *p != NULL; ++p) {
        cout << *p << endl;
    }

    return 0;
}

Otros consejos

En mi opinión, el uso más común es pasar referencia a una variable de puntero

void test(int ** var)
{
 ...
}

int *foo = ...
test(&foo);

Puede crear una matriz irregular multidimensional utilizando punteros dobles:

int ** array = new *int[2];
array[0] = new int[2];
array[1] = new int[3];

Un escenario común es cuando necesitas aprobar un nulo puntero a una función, inicializarlo dentro de esa función y usarlo fuera de la función.Sin indirección múltiple, la función que llama nunca tendría acceso al objeto inicializado.

Considere la siguiente función:

initialize(foo* my_foo)
{
    my_foo = new Foo();
}

Cualquier función que llame a 'initialize(foo*)' no tendrá acceso a la instancia inicializada de foo, porque el puntero que se pasa a esta función es una copia.(Después de todo, el puntero es solo un número entero, y los números enteros se pasan por valor).

Sin embargo, si la función se definiera así:

initialize(foo** my_foo)
{
    *my_foo = new Foo();
}

...y se llamaba así...

Foo* my_foo;

initialize(&my_foo);

...entonces la persona que llama tendría acceso a la instancia inicializada, a través de 'my_foo' - porque es el DIRECCIÓN del puntero que se pasó a 'inicializar'.

Por supuesto, en mi ejemplo simplificado, la función 'inicializar' podría simplemente devolver la instancia recién creada mediante la palabra clave return, pero eso no siempre es adecuado; tal vez la función necesite devolver algo más.

Si pasa un puntero como parámetro de salida, es posible que desee pasarlo como Foo** y establecer su valor como *ppFoo = pSomeOtherFoo.

Y desde el departamento de algoritmos y estructuras de datos, puede utilizar esa doble dirección indirecta para actualizar punteros, lo que puede ser más rápido que, por ejemplo, intercambiar objetos reales.

Un ejemplo simple sería usar int** foo_mat como una matriz 2D de números enteros.O también puedes usar punteros a punteros - digamos que tienes un puntero void* foo y tienes 2 objetos diferentes que tienen una referencia con los siguientes miembros: void** foo_pointer1 y void** foo_pointer2, al tener un puntero a un puntero, realmente puede verificar si *foo_pointer1 == NULL lo que indica que foo es NULL.No podrías comprobar si foo es NULL si foo_pointer1 fuera un puntero normal.Espero que mi explicación no haya sido demasiado complicada :)

carlos:Tu ejemplo debería ser:

*p = x;

(Tienes dos estrellas.) :-)

En C, el modismo es absolutamente necesario.Considere el problema en el que desea que una función agregue una cadena (C puro, por lo tanto un char *) a una matriz de punteros a char *.El prototipo de función requiere tres niveles de direccionamiento indirecto:

int AddStringToList(unsigned int *count_ptr, char ***list_ptr, const char *string_to_add);

Lo llamamos de la siguiente manera:

unsigned int   the_count = 0;
char         **the_list  = NULL;

AddStringToList(&the_count, &the_list, "The string I'm adding");

En C++ tenemos la opción de usar referencias, lo que produciría una firma diferente.Pero todavía necesitamos los dos niveles de indirección que preguntaste en tu pregunta original:

int AddStringToList(unsigned int &count_ptr, char **&list_ptr, const char *string_to_add);

Normalmente, cuando pasas un puntero a una función como valor de retorno:

ErrorCode AllocateObject (void **object);

donde la función devuelve un código de error de éxito/fracaso y completa el parámetro del objeto con un puntero al nuevo objeto:

*object = new Object;

Esto se usa mucho en la programación COM en Win32.

Esto es más una cosa de C, en C++ a menudo puedes envolver este tipo de sistema en una clase para hacer que el código sea más legible.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top