开发者

Passing a void* by reference

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 *&'

Casti开发者_JAVA百科ng it to void* doesn't work either

Also, are there any workarounds?


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜