4

I came across people passing data objects as:

declaration:

DataObject * data = 0;

calling it as:

SomeMethod( data );

definition of Somethod:

void SomeMethod(SomeObject * & object)

My obvious question is, when and why do you have to do this (& *)? Is it passing the pointer as reference?

ra170
  • 3,643
  • 7
  • 38
  • 52

5 Answers5

6

Is it passing the pointer as reference?

Yes, that's exactly what it is doing.

This is useful if you want to modify the pointer itself, rather than the data it is pointing to. Remember that C++ passes by value, so if you pass SomeObject*, you are passing a copy of the pointer to SomeObject.

Justin Ardini
  • 9,768
  • 2
  • 39
  • 46
4

Obviously if you want to modify the pointer's value (vs the pointee). The alternative would be a pointer to pointer.

For example, SomeMethod might allocate the object and now the caller has the pointer modified to point to that.

void foo(Bar*& p)
{
    p = new Bar(...);
    ...
}
UncleBens
  • 40,819
  • 6
  • 57
  • 90
  • 2
    Personally, I think a pointer to a pointer is the right answer on the rare occasions you actually need to do this - there's something about "*&" that makes my flesh crawl. But perhaps that's just me. –  Apr 14 '10 at 16:20
3

Yes, exactly!

So, not only can your function SomeMethod refer to the same data as the caller, but it can actually change what the caller points to!

int main() {
   SomeObject* data = new SomeObject(1);
   cout << data << " -> " << *data;  // "0xfffee314 -> 1"

   SomeMethod(data);
   cout << data << " -> " << *data;  // "0xeee32435 -> 2"
}

void SomeMethod(SomeObject*& object) {
   delete object;
   object = new SomeObject(2);
}
Andres Jaan Tack
  • 22,566
  • 11
  • 59
  • 78
2

It is passing the pointer as a reference. This is necessary if you intend to modify the pointer that you are passing to the function. For example:

void change(int *ptr)
{
    ptr = new int;
    *ptr = 5;
}
void change2(int *&ptr)
{
    ptr = new int;
    *ptr = 5;
}

int a = 4;
int *p = &a;
cout << *p << endl;
change(p);
cout << *p << endl;
change2(p);
cout << *p << endl;

This will output:

4
4
5

Edit: in addition to this, change() is leaking memory.

Niki Yoshiuchi
  • 16,883
  • 1
  • 35
  • 44
0

Consider the following C function:

void giveme(char **p) {
    *p = "Hello, World!";
}

Which gives you a string. If we were giving the string as a return value, we would have used just a pointer-to-char: char *giveme(), but since we use an out parameter we must have a pointer to whatever it is we want to return. In this case a pointer to a pointer to char.

One case where you'd meet such code is COM, where the basic function QueryInterface is defined as:

HRESULT QueryInterface(
  [in]   REFIID riid,
  [out]  void **ppvObject
);

In the following code we want get an IUnknown somehow, and want to set the pointer pWhatever to point to the IWhatever interface of our object. We call QueryInterface the following way:

IUnknown *pUnk = getIUnknownFromWherever();
IWhatever *pWhatever = NULL;
HRESULT hr;
hr = pUnk->QueryInterface(IID_IWHATEVER, &pWhatever);

Since we want QueryInterface to change the pointer, rather than the pointee (the object it point to) we need to give it the address of the pointer.

Now, the whole point of C++ references is to make life easier in some common scenarios when pointers are used in C. One of them is out parameters. So, the previous two code fragments in C++ could have been:

// Assume IUnknown::QueryInterface was defined as:
HRESULT QueryInterface(
  [in]   REFIID riid,
  [out]  void *&ppvObject
);

// Now using it could have been somewhat less verbose
// and error prone thanks to references:
IUnknown *pUnk = getIUnknownFromWherever();
IWhatever *pWhatever = NULL;
HRESULT hr;
hr = pUnk->QueryInterface(IID_IWHATEVER, pWhatever);
// We're not passing pWhatever, but rather a reference to
// it - but since it's a C++ reference rather than a pointer,
// we don't need to explicitly use the address-of(&) operator

And that's it. The point of passing a pointer as reference is basically the same as passing any parameter as non-const reference - have the callee change it. Here we want a pointer (rather than an int or a double) changed so we pass a reference to a pointer.

conio
  • 3,681
  • 1
  • 20
  • 34