views:

337

answers:

11

Pointers-to-pointers and references-to-pointers seem overly complicated at first, especially for newbies. What is the best and most useful reason you used one in a c/c++ project you worked on?

This can help people better understand pointers and how to use them effectively.

Edited: Included C as well as C++

+2  A: 

Pointers-to-pointers? Dynamically allocated 2D arrays!

Jacob
I use simple pointers for those. Works much better, and arguably easier (if you want the dimensions to be truly dynamic!).
Konrad Rudolph
Anytime you want a dynamically allocated array pointers to pointers are essential. Anytime you want a dynamically sized array too (one that can change size).
Daniel Bingham
@Konrad If your array is storing objects then it's better to use a pointer to a pointer. That way you can shift the objects around with out doing a whole object copy.
Daniel Bingham
To be perfectly honest, I use vector<vector<T>> for my 2D arrays nowadays, but not such a long time ago pointer-to-pointers did the job!
Jacob
@Alcon: Yep, very true.
Jacob
@Alcon: what do you mean with shifting objects around without doing a copy?
Konrad Rudolph
@Konrad If you have an array of objects, and it's going to be dynamic in size (IE you'll be adding and deleting) then you're going to want to be able to shift objects around. Also if you wanna keep it ordered, you'll need to move them around with in the array. If you use a single pointer array ie: object *array = new object[10], then if you try and do that, you'll be copying a whole object using its copy constructor each time. If you use a double pointer array: object **array = new object[10], and then for each item you do array[1] = new object(); you'll just copy the pointer when you move
Daniel Bingham
A: 

Well, char **argv and dynamically allocated two-dimensional jagged arrays in general are both pretty damn useful.

Reference to pointer is useful anytime you want to allow the callee to change the pointer (not what the pointer is pointing to). For example, someone that is dynamically providing memory:

void feedMeSeymour(void *&p, int size) {
    p = new char[size];
}
Jason
2D jagged arrays can be `vector<vector<>>` and a structure like `argv` can be `vector<string>`…
Potatoswatter
+4  A: 

Pointers to pointers are very commonly used as parameters that allocate & return a buffer, such as a string:

void SetValue(char** buf)
{
    string s = "Hello, Ptr Ref";
    *buf = new char[s.length()+1];
    copy(s.begin(), s.end(), *buf);
    (*buf)[s.length()] = 0;
}


int main()
{
    char* buf = 0;
    SetValue(&buf);
    cout << buf;
    delete [] buf;
    return 0;
}

Similarly, instead of passing in a pointer to a pointer to the buffer you want to allocate & modify, you can pass in a reference to that buffer. This can help to clarify the semantics of your function to the caller, so that they don't do something like call SetValue(0);

void SetValue(char*& buf)
{
    string s = "Hello, Ptr Ref";
    buf = new char[s.length()+1];
    copy(s.begin(), s.end(), buf);
    buf[s.length()] = 0;
}


int main()
{
    char* buf = 0;
    SetValue(buf);
    cout << buf;
    delete [] buf;
    return 0;
}

But even while the semantics of SetValue(char*&) might be a bit clearer than the SetValue(char**) version, there is still room for improvement. The question of who owns the resulting pointer comes to mind.

Keep in mind that while these examples are simplistic and contrived, implementations like this abound. In many of those cases where this is being done you have no choice -- for example, when calling WINAPI functions like FormatMessage() and asking it to allocate the buffer. But in many other cases where you write the function, there will be other ways to skin the cat. Arguably, better ways. Such as:

string GimmeValue()
{
  return "Hello, String";
}

This might be better for a variety of reasons. It is (potentially) semantically more clear to return a value by value than to use outvals like pointers-to-pointer because the question of ownership is easily resolved. It is often better to avoid using operator new in places when a stack-allocated variable will do just fine, because you avoid potential memory leaks or defects due to deleteing the buffer more than once.

John Dibling
Any *buffer* passed in (eg, data pointed to by char *) can be modified (whether its a good idea, depends on the implementation details) - you need a pointer to a pointer if you want to return a new buffer altogether so that you can modify the pointer itself.
Ruddy
@Ruddy: Clarified wording a bit. Cheers.
John Dibling
Comptrol
A: 

Say you want to return a buffer that you've allocated - or you might need to reallocate one passed in.

You can either return a pointer to the buffer, or have the caller pass in the address of a pointer (so you have a pointer to a pointer), and set that pointer to point to your buffer.

Anon.
A: 

COM - any method that returns an interface has to be handed a pointer to a pointer parameter to be able to.

Ruddy
True. Fundamentally the reason this is so is because the called function (such as CoCreateInstance) allocates the object. Typically the way the WINAPI handles this is by taking ptr-to-ptr outval parameters.
John Dibling
A: 

I once used a char ***arg parameter to a function to update a dynamically allocated argv-like array in place and also to scare the begeebies out of my co-workers.

Richard Pennington
+2  A: 

I can hardly remember the last time I used either one directly. Mostly, they're useful for doing things like implementing your own container classes -- for example, if you want to allocate a node in a linked list, you have pointers between the nodes, and if you want to modify a pointer that's been passed to your function, you need either a reference or a pointer to that pointer.

Of course, you can also use pointers to pointers to create pseudo-2D arrays as well. If you really need a square array they're not a particularly good choice, but if you want a "ragged array" (e.g. an array of strings, each of a potentially different length) it's useful.

Pointers to pointers are nearly unavoidable in C, but in C++ the standard library already has container classes -- for example, if you want a dynamic array of dynamically-sized strings in C, nearly your only choice is to start with a char **, and allocate the pieces dynamically. In C++, you usually want to use a std::vector<std::string> instead. You still run into them when/if you decide to implement your own containers, but that's a fairly rare occurrence (at least that you have to start from raw pointers and such instead of building on top of existing containers).

Jerry Coffin
+1 - I hardly ever even use single raw pointers. Smart pointers and stl/boost containers pretty much cover their uses (except in implementing smart pointers or containers)
Eclipse
A: 

Pointers to pointer are also good for creating an array of mixed length arrays. I think they are commonly called rigid jagged arrays. I have used this before to reduce memory usage on an embedded system.

mholzmann
`std::vector` does this more cleanly. If you don't want its extra wiggle room, you're probably better off finding another container class (in Boost maybe) than doing it the C way.
Potatoswatter
+2  A: 

Since no one has mentioned this yet, they may be useful as iterators.

Assume you have a list of objects of some sort. And you need to traverse some of them in some specific order.

So you create an array holding pointers to the objects you need to traverse, and then you sort that array.

An iterator into that array is a pointer to a pointer.

Sorting it with std::sort requires a pair of iterators, which means that it requires a pair of pointers to pointers.

And then traversing it with std::for_each also requires a pair of iterators.

That's the context in which I last used pointers to pointers. (I actually had one final layer of abstraction so I ended up with pointers to pointers to pointers, but that's probably more unusual)

jalf
“An iterator into that array is a pointer to a pointer.” – why not simply a pointer? `int*` is an iterator into `int[]`, no sweat, no double indirection needed.
Konrad Rudolph
In my case, the "original" collection is a custom-made singly linked list. Now, I needed to perform certain operations on a subset of the elements in that list, and I needed to perform those operations in a different order than the one in which they exist in the list.So I created a secondary array containing pointers to the specific objects I wanted to work on, and then I sorted *that* array. That is an array of pointers, and to sort it, I then need an iterator pair, or pointers to two of these pointers.
jalf
The important thing is that the original list should not be modified or otherwise affected. It should contain the same elements in the same order. Copying the objects in that list was not an option, and modifying the list in any other way wasn't either.
jalf
Very interesting, so far I think this is the most unique solution I've seen yet.
Brian T Hannan
Yep, that's why I wanted to mention it. People always mention the usual suspects (return a pointer to allocated data through a function parameter, or 2d arrays). I like this one because on one hand it's less obvious, but on the other, it's also nothing special at all. We're used to pointers being used as iterators, and seeing containers holding pointers is fairly common too. And if that container is an array, then the iterators turn out to be double pointers, possibly without the programmer even realizing he's using them.
jalf
You are the winner, b/c I had to chose the most useful, interesting and unique way to use pointer-to-pointers. Thanks for your answer!
Brian T Hannan
A: 

Sort function for a templated sorted vector. This is a rather realistic example:

template <typename T>
class Vector {
public:
    typedef bool SortFunc(const T& left, const T& right) ;
    void SetSort(SortFunc* pFunc){}
};


bool intSort(const int& left, const int& right)
{
    return true;
}

bool pintSort( int* const & left, int* const & right)
{
    return true;
}

//in main

Vector<int> intVec;
Vector<int*> pintVec;

intVec.SetSort(&intSort);
pintVec.SetSort(&pintSort);

Considering the fact that we could pass anything as a vector parameter, using const references as sort function parameters is rather sane. What is not sane though, is working out how to string the bloody asterisks, ampersands and consts in order to achive a const reference to non-const integer pointer.

Igor Zevaka
+1  A: 

Passing around an array of values representing the contents of a TIFF file for geoprocessing.

wheaties