Why can't I pass a void*
by reference? The compiler allows me to declare a function with the following signature:
static inline void FreeAndNull(void*& item)
But when I try to call it, I get the following error:
Error 1 error C2664: 'FreeAndNull' : cannot convert parameter 1 from 'uint8_t *' to 'void *&'
Casting it to void*
doesn't work either
Also, are there any workarounds?
which basically: declares a variable named p which is a pointer to type void (and pointers to void are compatible with pointers to any object type without requiring any explicit cast, including pointers to pointers to void — which is the type of &p );
A reference to a void sufferes from the same problem, by definition the data pointed to doesn't have a type, therefore it can't be referenced in any meaningful way. To reference it you - the programmer - need to cast it to another type, then you can have a typed reference to it.
Pass by reference (also called pass by address) means to pass the reference of an argument in the calling function to the corresponding formal parameter of the called function so that a copy of the address of the actual parameter is made in memory, i.e. the caller and the callee use the same variable for the parameter.
Passing by reference literally just means passing the memory address of where a variable is stored rather than the variable's value itself. That is what C allows, and it is pass-by-reference every time you pass a pointer, because a pointer is a reference to a variables memory location.
The answer is yes, you can pass a void*
by reference, and the error you're getting is unrelated to that. The problem is that if you have a function that takes void*
by reference, then you can only pass in variables that actually are void*
s as a parameter. There's a good reason for this. For example, suppose you have this function:
void MyFunction(void*& ptr) {
ptr = malloc(137); // Get a block of raw memory
}
int* myIntArray;
MyFunction(myIntArray); // Error- this isn't legal!
The above code is illegal because of the indicated call, and for good reason. If we could pass in myIntArray
into MyFunction
, it would get reassigned to point to a buffer of type void*
that isn't an int
array. Consequently, on return from the function your int*
would be pointing at an array of type void*
, subverting the type system. This isn't to say that C++ has a strong type system - it doesn't - but if you're going to subvert it you have to explicitly put some casts in.
You similarly can't do this:
void MyFunction(void*& ptr) {
ptr = malloc(137); // Get a block of raw memory
}
int* myIntArray;
MyFunction((void*)myIntArray); // Error- this isn't legal!
As a good reference as to why you can't do this, think about this code:
void OtherFunction(int& myInt) {
myInt = 137;
}
double myDouble;
OtherFunction((int)myDouble); // Also error!
This isn't legal because if you tried passing in a double
into a function that took an int&
, then since int
and double
have fundamentally different binary representations, you'd end up clobbering the bits of the double
with meaningless data. If this cast were to be legal, it would be possible to do Bad Things like this.
So in short, yes, you can take in a void* &
, but if you do you have to pass in real void*
s. As Erik pointed out above, if you want to free and zero a pointer templates are the way to go.
If you really do want to pass in a uint_8*
into this your function, you could do so like this:
uint_8* uPtr = /* ... */
void* ptr = uPtr;
FreeAndNull(ptr);
uPtr = (uint_8*) ptr;
This requires explicit casting to tell the compiler "Yes, I know this may be unsafe, but I'm going to do it anyway."
Hope this helps!
If you take a void * by reference, you have to pass an actual void *, not an uint8_t *.
Try this instead:
template<typename T> inline void FreeAndNull(T * & V) { free(V); V = 0; }
EDIT: Modified sample to better reflect the OP's function name, and to address @6502's entirely correct comment.
Casting to void* doesn't work for a reason much simpler than what is being explained elsewhere: casting creates rvalues unless you explicitly specify a reference. You can't pass an rvalue off as a non-const reference.
Prove it? Try this:
void fun(void * &) {}
int main() { int * x; void * x2 = x; fun(x); }
If it's appropriate for you use, try this:
void fun(void * const&);
Now not only does casting work, its implicit.
Casting to reference can be dangerous. It does actually cause your code to compile but I won't speak to its behavior:
void fun(void *&){}
int main() { int * x; fun((void*&)x); }
My bet is that this will do very-bad-things(tm) since you're actually doing a reinterpret_cast here rather than a static cast.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With