Are implicit casts to void*& illegal?

R

Ray Gardener

I searched around but couldn't find any previous discussion on this, so...

I have a macro that implements a common memory disposal function, e.g.:

#define safe_free(void* pv) if(pv) { ::free(pv); (pv) = NULL; }

(Yes, its free() instead of operator delete, but I don't think using the
newer memory semantics matters in this case.)

Since another project might have an entity of the same name, and macros
are in the global namespace, to avoid namespace collision I thought an
inline function might be better:

namespace myspace
{
inline void safe_free(void*& pv) { ... }
}

(Having pv as a void*& lets pv be assigned to NULL).


However, calling code can no longer do this:

using namespace myspace;
char* p = (char*)::malloc(100);
safe_free(p); // error: char* cannot be
// converted to void*&.


Doing

safe_free((void*)p);

fails also (can't convert void* to void*&), which seems odd because

void* pv = (void*)p;
safe_free(pv);

works fine.

So to use the function, I wound up doing

safe_free((void*&)p);

which is not the end of the world but tragically inelegant considering
that references usually increase elegance. Implicit casts to void* are
legal, but not void*& -- strange.

This is happening in MSVC 6. I was wondering if others had the same
problem in other compilers or other versions of MSVC.

This template would work:

template <type T> void safe_free(T*& p)
{ ... }

but it seems like overkill to have to instantiate a template function
for all possible pointer types when the function only needs the
pointer's value, not the type of object being pointed to.

Ray
 
V

Victor Bazarov

Ray said:
I searched around but couldn't find any previous discussion on this,
so...
I have a macro that implements a common memory disposal function,
e.g.:
#define safe_free(void* pv) if(pv) { ::free(pv); (pv) = NULL; }

Actually, you need to drop the "void*" part. And there is no need to
check for its null-ness. 'free' does nothing if you pass a null pointer
to it.
(Yes, its free() instead of operator delete, but I don't think using
the newer memory semantics matters in this case.)

They may not, but only if the pointer is obtained from 'malloc' or
'realloc'. If you get the pointer from 'new', you can't 'free' it.
Since another project might have an entity of the same name, and
macros are in the global namespace, to avoid namespace collision I
thought an inline function might be better:

namespace myspace
{
inline void safe_free(void*& pv) { ... }
}

(Having pv as a void*& lets pv be assigned to NULL).
OK.

However, calling code can no longer do this:

using namespace myspace;
char* p = (char*)::malloc(100);
safe_free(p); // error: char* cannot be
// converted to void*&.

Make your 'safe_free' a template.
Doing

safe_free((void*)p);

fails also (can't convert void* to void*&), which seems odd because

void* pv = (void*)p;
safe_free(pv);

works fine.

So to use the function, I wound up doing

safe_free((void*&)p);

which is not the end of the world but tragically inelegant considering
that references usually increase elegance. Implicit casts to void* are
legal, but not void*& -- strange.

Yes, and it should be dropped.
This is happening in MSVC 6. I was wondering if others had the same
problem in other compilers or other versions of MSVC.

This template would work:

template <type T> void safe_free(T*& p)
{ ... }

That's right! It is perfect.
but it seems like overkill to have to instantiate a template function
for all possible pointer types when the function only needs the
pointer's value, not the type of object being pointed to.

It's not overkill. Declare it 'inline' and forget about it.

V
 
R

Ray Gardener

Yes, you're right; I forgot that this is an inline function anyway.
Sigh... got so paranoid about template instantation bloat I've let it
get the better of me. :)

Thanks,
Ray
 
P

peter koch

Ray said:
Yes, you're right; I forgot that this is an inline function anyway.
Sigh... got so paranoid about template instantation bloat I've let it
get the better of me. :)

Thanks,
Ray
[snip]

Actually i do not believe there is any reason to worry about template
bloat these days. Improvements in the linker and compiler have come a
far way - to an extent that code from different templates will be
merged if the code is the same. This happens for e.g.
std::vector::push_back which is the same code for int and unsigned int.
So even if your code was not inline, most probably all instantations
would fold to the same code.

/Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top