Domanda

In quali circostanze potresti voler utilizzare più riferimenti indiretti (ovvero una catena di puntatori come in Foo **) in C++?

È stato utile?

Soluzione

L'utilizzo più comune, come sottolineato da @aku, è consentire che una modifica a un parametro del puntatore sia visibile dopo il ritorno della funzione.

#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;
}

Questo verrà stampato

12

Ma ci sono molti altri usi utili come nell'esempio seguente per ripetere un array di stringhe e stamparle sullo standard output.

#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;
}

Altri suggerimenti

L'utilizzo più comune dell'IMO è passare il riferimento alla variabile puntatore

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

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

Puoi creare un array frastagliato multidimensionale utilizzando doppi puntatori:

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

Uno scenario comune è quello in cui è necessario superare un file nullo puntatore a una funzione e averlo inizializzato all'interno di quella funzione e utilizzato all'esterno della funzione.Senza l'indirizzamento multiplo, la funzione chiamante non avrebbe mai accesso all'oggetto inizializzato.

Consideriamo la seguente funzione:

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

Qualsiasi funzione che chiama 'initialize(foo*)' non avrà accesso all'istanza inizializzata di Pippo, perché il puntatore passato a questa funzione è una copia.(Dopo tutto il puntatore è solo un numero intero e gli interi vengono passati per valore.)

Tuttavia, se la funzione fosse definita in questo modo:

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

...e si chiamava così...

Foo* my_foo;

initialize(&my_foo);

...allora il chiamante avrebbe accesso all'istanza inizializzata, tramite 'my_foo' - perché è il indirizzo del puntatore passato per "inizializzare".

Naturalmente, nel mio esempio semplificato, la funzione 'initialize' potrebbe semplicemente restituire l'istanza appena creata tramite la parola chiave return, ma ciò non sempre è adatto: forse la funzione deve restituire qualcos'altro.

Se passi un puntatore come parametro di output, potresti volerlo passare come Foo** e impostarne il valore come *ppFoo = pSomeOtherFoo.

E dal reparto algoritmi e strutture dati, puoi utilizzare questo doppio riferimento indiretto per aggiornare i puntatori, il che può essere più veloce rispetto, ad esempio, allo scambio di oggetti reali.

Un semplice esempio potrebbe essere l'utilizzo int** foo_mat come array 2d di numeri interi.Oppure puoi anche usare puntatori a puntatori: diciamo che hai un puntatore void* foo e hai 2 oggetti diversi che hanno un riferimento ad esso con i seguenti membri: void** foo_pointer1 E void** foo_pointer2, avendo un puntatore a un puntatore puoi effettivamente verificare se *foo_pointer1 == NULL che indica che foo è NULL.Non saresti in grado di verificare se foo è NULL se foo_pointer1 fosse un puntatore normale.Spero che la mia spiegazione non sia stata troppo confusa :)

Carlo:Il tuo esempio dovrebbe essere:

*p = x;

(Hai due stelle.) :-)

In C l'idioma è assolutamente obbligatorio.Considera il problema in cui vuoi che una funzione aggiunga una stringa (C puro, quindi un char *) a un array di puntatori a char *.Il prototipo della funzione richiede tre livelli di indirezione:

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

Lo chiamiamo così:

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

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

In C++ abbiamo invece la possibilità di utilizzare i riferimenti, che produrrebbero una firma diversa.Ma abbiamo ancora bisogno dei due livelli di riferimento indiretto che hai chiesto nella tua domanda originale:

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

Di solito quando si passa un puntatore a una funzione come valore restituito:

ErrorCode AllocateObject (void **object);

dove la funzione restituisce un codice di errore di successo/fallimento e compila il parametro dell'oggetto con un puntatore al nuovo oggetto:

*object = new Object;

Questo è molto utilizzato nella programmazione COM in Win32.

Questa è più una cosa da fare in C, in C++ puoi spesso racchiudere questo tipo di sistema in una classe per rendere il codice più leggibile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top