Pergunta

Sob quais circunstâncias você pode querer usar indireção múltipla (ou seja, uma cadeia de ponteiros como em Foo **) em C++?

Foi útil?

Solução

O uso mais comum, como @aku apontou, é permitir que uma alteração em um parâmetro de ponteiro fique visível após o retorno da função.

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

Isto irá imprimir

12

Mas existem vários outros usos úteis, como no exemplo a seguir, para iterar uma matriz de strings e imprimi-las na saída padrão.

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

Outras dicas

O uso mais comum da IMO é passar referência para variável de ponteiro

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

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

Você pode criar uma matriz irregular multidimensional usando ponteiros duplos:

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

Um cenário comum é onde você precisa passar por um nulo ponteiro para uma função e inicializá-lo dentro dessa função e usá-lo fora da função.Sem indireção múltipla, a função de chamada nunca teria acesso ao objeto inicializado.

Considere a seguinte função:

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

Qualquer função que chame 'initialize(foo*)' não terá acesso à instância inicializada de Foo, porque o ponteiro passado para esta função é uma cópia.(Afinal, o ponteiro é apenas um número inteiro e os números inteiros são passados ​​​​por valor.)

No entanto, se a função foi definida assim:

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

...e foi chamado assim...

Foo* my_foo;

initialize(&my_foo);

...então o chamador teria acesso à instância inicializada, via 'my_foo' - porque é o endereço do ponteiro que foi passado para 'inicializar'.

É claro que, no meu exemplo simplificado, a função 'initialize' poderia simplesmente retornar a instância recém-criada através da palavra-chave return, mas isso nem sempre é adequado - talvez a função precise retornar outra coisa.

Se você passar um ponteiro como parâmetro de saída, você pode querer passá-lo como Foo** e defina seu valor como *ppFoo = pSomeOtherFoo.

E do departamento de algoritmos e estruturas de dados, você pode usar essa dupla indireção para atualizar ponteiros, o que pode ser mais rápido do que, por exemplo, trocar objetos reais.

Um exemplo simples seria usar int** foo_mat como uma matriz 2d de inteiros.Ou você também pode usar ponteiros para ponteiros - digamos que você tenha um ponteiro void* foo e você tem 2 objetos diferentes que fazem referência a ele com os seguintes membros: void** foo_pointer1 e void** foo_pointer2, tendo um ponteiro para um ponteiro, você pode realmente verificar se *foo_pointer1 == NULL o que indica que foo é NULL.Você não seria capaz de verificar se foo é NULL se foo_pointer1 fosse um ponteiro normal.Espero que minha explicação não tenha sido muito confusa :)

Carlos:Seu exemplo deveria ser:

*p = x;

(Você tem duas estrelas.) :-)

Em C, o idioma é absolutamente necessário.Considere o problema no qual você deseja que uma função adicione uma string (C puro, portanto um char *) a uma matriz de ponteiros para char *.O protótipo da função requer três níveis de indireção:

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

Chamamos isso da seguinte forma:

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

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

Em C++ temos a opção de usar referências, o que geraria uma assinatura diferente.Mas ainda precisamos dos dois níveis de indireção que você perguntou na sua pergunta original:

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

Normalmente, quando você passa um ponteiro para uma função como valor de retorno:

ErrorCode AllocateObject (void **object);

onde a função retorna um código de erro de sucesso/falha e preenche o parâmetro do objeto com um ponteiro para o novo objeto:

*object = new Object;

Isso é muito usado na programação COM no Win32.

Isso é mais uma coisa de C, em C++ muitas vezes você pode agrupar esse tipo de sistema em uma classe para tornar o código mais legível.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top