Question

Dans quelles circonstances pouvez-vous utiliser plusieurs indirection (c'est-à-dire une chaîne de pointeurs comme dans Foo ** ) en C ++?

Était-ce utile?

La solution

Comme @aku l'a souligné, l'utilisation la plus courante consiste à autoriser la modification d'un paramètre de pointeur après le retour de la fonction.

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

Ceci imprimera

12

Mais il existe plusieurs autres utilisations utiles, comme dans l'exemple suivant, pour itérer un tableau de chaînes et les imprimer sur la sortie standard.

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

Autres conseils

L’utilisation la plus courante de l’OMI consiste à transmettre une référence à la variable de pointeur

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

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

Vous pouvez créer un tableau multidimensionnel en pointillés à l'aide de doubles pointeurs:

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

Un scénario courant consiste à passer un pointeur null à une fonction, à l'initialiser dans cette fonction et à l'utiliser en dehors de la fonction. Sans indirection multiple, la fonction appelante n’aurait jamais accès à l’objet initialisé.

Considérez la fonction suivante:

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

Toute fonction qui appelle "initialize (foo *)" n'aura pas accès à l'instance initialisée de Foo , car le pointeur transmis à cette fonction est une copie. (Le pointeur n’est finalement qu’un entier, et les entiers sont passés par valeur.)

Cependant, si la fonction a été définie comme ceci:

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

... et ça s'appelait comme ça ...

Foo* my_foo;

initialize(&my_foo);

... alors l'appelant aurait accès à l'instance initialisée via "my_foo" - car il s'agit de l'adresse du pointeur qui a été transmis à "initialize".

Bien sûr, dans mon exemple simplifié, la fonction 'initialiser' pourrait simplement renvoyer l'instance nouvellement créée via le mot clé return, mais cela ne convient pas toujours - peut-être que la fonction doit renvoyer autre chose.

Si vous transmettez un pointeur en tant que paramètre de sortie, vous pouvez le transmettre sous la forme Foo ** et lui attribuer la valeur * ppFoo = pSomeOtherFoo .

Et à partir du service des algorithmes et des structures de données, vous pouvez utiliser cette double indirection pour mettre à jour les pointeurs, ce qui peut être plus rapide que par exemple l'échange d'objets réels.

Un exemple simple consisterait à utiliser int ** foo_mat en tant que tableau 2d d'entiers. Ou vous pouvez également utiliser des pointeurs vers des pointeurs - disons que vous avez un pointeur void * foo et que vous avez 2 objets différents qui y sont référencés avec les membres suivants: void ** foo_pointer1 et void ** foo_pointer2 , en ayant un pointeur sur un pointeur, vous pouvez réellement vérifier si * foo_pointer1 == NULL indique que foo est NULL. Vous ne pourriez pas vérifier si foo est NULL si foo_pointer1 était un pointeur normal. J'espère que mon explication n'était pas trop compliquée:)

Carl: votre exemple devrait être:

*p = x;

(Vous avez deux étoiles.): -)

En C, l’idiome est absolument nécessaire. Considérez le problème dans lequel vous voulez qu'une fonction ajoute une chaîne (C pur, donc un char *) à un tableau de pointeurs sur char *. Le prototype de fonction nécessite trois niveaux d’indirection:

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

Nous l'appelons comme suit:

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

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

En C ++, nous avons la possibilité d’utiliser des références, ce qui donnerait une signature différente. Mais nous avons toujours besoin des deux niveaux d'indirection que vous avez évoqués dans votre question initiale:

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

Habituellement, lorsque vous passez un pointeur sur une fonction en tant que valeur de retour:

ErrorCode AllocateObject (void **object);

où la fonction renvoie un code d'erreur de réussite / échec et remplit le paramètre d'objet avec un pointeur sur le nouvel objet:

*object = new Object;

Ceci est beaucoup utilisé dans la programmation COM sous Win32.

C’est plus une chose à faire en C; en C ++, vous pouvez souvent envelopper ce type de système dans une classe pour rendre le code plus lisible.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top