tags:

views:

1265

answers:

8

Under what circumstances might you want to use multiple indirection (that is, a chain of pointers as in **foo) in C++?

+4  A: 

IMO most common usage is to pass reference to pointer variable

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

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

You can create multidimensional jagged array using double pointers:

int ** array = new *int[2];
array[0] = new int[2];
array[1] = new int[3];
aku
Careful - "int ** var" is not a reference to a pointer but a pointer to a pointer.
Konrad
+3  A: 

If you pass a pointer in as output parameter, you might want to pass it as Foo** and set its value as *ppFoo = pSomeOtherFoo.

And from the algorithms-and-data-structures department, you can use that double indirection to update pointers, which can be faster than for instance swapping actual objects.

Carl Seleborg
+1  A: 

A simple example would be using int** foo_mat as a 2d array of integers. Or you may also use pointers to pointers - lets say that you have a pointer void* foo and you have 2 different objects that have a reference to it with the following members: void** foo_pointer1 and void** foo_pointer2, by having a pointer to a pointer you can actually check whether *foo_pointer1 == NULL which indicates that foo is NULL. You wouldn't be able to check whether foo is NULL if foo_pointer1 was a regular pointer. I hope that my explanation wasn't too messy :)

dudico
+1  A: 

Usually when you pass a pointer to a function as a return value:

ErrorCode AllocateObject (void **object);

where the function returns a success/failure error code and fills in the object parameter with a pointer to the new object:

*object = new Object;

This is used a lot in COM programming in Win32.

This is more of a C thing to do, in C++ you can often wrap this type of system into a class to make the code more readable.

Skizz

Skizz
+1  A: 

Carl: Your example should be:

*p = x;

(You have two stars.) :-)

0124816
Oh, yeah, you're right. Fixed, thanks!
Carl Seleborg
+4  A: 

One common scenario is where you need to pass a null pointer to a function, and have it initialized within that function, and used outside the function. Without multplie indirection, the calling function would never have access to the initialized object.

Consider the following function:

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

Any function that calls 'initialize(foo*)' will not have access to the initialized instance of Foo, beacuse the pointer that's passed to this function is a copy. (The pointer is just an integer after all, and integers are passed by value.)

However, if the function was defined like this:

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

...and it was called like this...

Foo* my_foo;

initialize(&my_foo);

...then the caller would have access to the initialized instance, via 'my_foo' - because it's the address of the pointer that was passed to 'initialize'.

Of course, in my simplified example, the 'initialize' function could simply return the newly created instance via the return keyword, but that does not always suit - maybe the function needs to return something else.

Konrad Rudolph
+7  A: 

Most common usage as @aku pointed out is to allow a change to a pointer parameter to be visible after the function returns.

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

This will print

12

But there are several other useful usages as in the following example to iterate an array of strings and print them to the 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;
}
smink
+1  A: 

In C, the idiom is absolutely required. Consider the problem in which you want a function to add a string (pure C, so a char *) to an array of pointers to char *. The function prototype requires three levels of indirection:

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

We call it as follows:

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

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

In C++ we have the option of using references instead, which would yield a different signature. But we still need the two levels of indirection you asked about in your original question:

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