5

I'm looking through an API written in C++ and I'm confused as to what the following parameter type means:

void*& data

Does that mean the user would pass in a reference to a void pointer? If that's true, what's the point? I mean void* is already indirected so why would you ever want to redirect it again?

wwahammy
  • 467
  • 1
  • 5
  • 14

3 Answers3

7

void * means pass-by-pointer in C++, meaning you pass in a pointer, but it's actually a copy of the pointer. If you modified this pointer in your function, like changing its address, it is not reflected in the pointer you passed in.

Combining that with pass by reference, void *& means you are passing an alias of the original pointer to this function. If you modified it, like changing its address, it will be reflected in the original pointer.

wkl
  • 77,184
  • 16
  • 165
  • 176
  • I think pass-by-pointer in this case is kind of a misnomer; void* is just a data type which stores an address. void*& is just C++ syntactic sugar for void**, another data type which stores an address. If you go to the address stored by a void**, you'll find a void*. – eplawless Nov 20 '10 at 20:08
  • 4
    @eplawless: References are not syntactic sugar for pointers. They are usually implemented using pointers, that's it. Consider e.g. that references can't be reseated, that they are (language-wise) only aliases instead of separate variables and that they can be used to extend the life-time of a temporary. – Georg Fritzsche Nov 20 '10 at 20:12
  • @Georg: Only C++0x rvalue references can be bound to a temporary within a function. If you mean via parameter passing, they are still syntactic sugar for pointers: your object is created on the stack, and a pointer to the object on the stack is passed into your function. You're right that they've encoded additional constraints into references, but at the end of the day they're nothing more than constrained pointers and their capabilities are still a subset of pointers'. I find it much more useful to think of them in those terms while developing in C++. – eplawless Nov 20 '10 at 20:17
  • @eplawless: I meant `const A& a = A();` or `const B& b = func();`. Also consider `A a; A& b = a;`, where every sane compiler will simply use `b` as an alias for `a`. If references only have a subset of pointer functionality, how would you do the same with pointers? – Georg Fritzsche Nov 20 '10 at 20:23
  • @Georg: for the first part, my apologies and you're correct: const references *can* be bound to temporaries to extend their lifetime, I'd forgotten that that was the case. In the compiler optimization case you give, assuming A* b = &a; and that the compiler is able to prove that b is not aliased further, it should make the same optimization. I'm still not convinced of the fundamental difference of references, in the first case; the code generated by the compiler will result on the temporary being stored on the stack, and operations being carried out on that memory address. – eplawless Nov 20 '10 at 20:32
  • @Georg: I appreciate the discussion though, thanks for humouring me :) – eplawless Nov 20 '10 at 20:36
  • @eplawless: Well, there is a difference between saying *"it should have the same effects with compiler X"* and it being guaranteed language wise. As you say yourself, the compiler would have to prove that it is the same while for references it is guaranteed, language-wise, to be the same. Also don't forget that references have to be initialized, are not separate objects from the language viewpoint, etc. – Georg Fritzsche Nov 26 '10 at 07:36
2

It's tough to say without seeing it's use, but you point out that a reference is a level of indirection. Would you find it weird if it was a pointer to a pointer? Those are quite common - in fact you deal with them when accepting command line arguments and get pointers to char pointers. Another example would be if you were making a hash map using buckets, and wanted to be able to return the pointer to the pointer that started the bucket.

The point being is that sometimes you need multiple levels of indirection. It is true that mixing pointers and references can be quirky, but there are good reasons for it. One common reason is the need for C++ code to interact with C apis. A lot of POSIX system calls require void pointers that get passed in and then changed, so the C++ function in question may be acting as a wrapper around that.

Bill Prin
  • 2,498
  • 1
  • 20
  • 27
  • I see what you're saying. I've seen a `void**` before but never `void*&`. I guess when you think it through it all makes sense. – wwahammy Nov 20 '10 at 20:15
1

But be careful to not return reference to local void*. Don't do something like this:

void*& f()
{
 int* a=new int(10);
 void* x=(void*)a;
 return x;
}
Mihran Hovsepyan
  • 10,810
  • 14
  • 61
  • 111
  • why shouldn't do this, I test it, it works ok, you mean it's same like `void* f()`? – toolchainX Nov 02 '12 at 16:47
  • It is UB (undefined behavior), so it can work sometimes. But not always. In your case, possibly, you called `f()` then tried to use the value it returned right after the function call, and the stack created for local variables inside `f()` wasn't rewritten by that time, but if you tried to call `f()`, then do some work (declare some new variables, call functions) you would fail. – Mihran Hovsepyan Nov 06 '12 at 09:29