Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

malloc/free in C++: why does free not accept a const void*, and is there a better way? [duplicate]

Tags:

c++

c

Interfacing C++11 code to some C callbacks, and I have to pass const char * const *, i.e. an array of strings. Here is a cut-down version of my code:

int main(int,char**){
  const int cnt = 10;
  const char * const * names =
    static_cast<const char * const *>(malloc( sizeof(char*) * cnt));
  //... allocating names[0], etc. coming soon ...
  the_c_function(names);
  free(names);
  return 0;
}

So I worked out how to use malloc in C++, but I'm stuck on free, as it tells me: "invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]"

My first reaction was "Eh? Why do you care, all you have to do is free the pointer." Second reaction was to just cast it away. But this gets rejected by the compiler:

free( const_cast<void*>(names) );

And this does too:

free( static_cast<void*>(acctnames) );

E.g. "invalid static_cast from type ‘const char* const*’ to type ‘void*’".

What does work is a good 'ole C cast:

free( (void*)(acctnames) );

Is that safe, or am I missing something here? (valgrind tells me "All heap blocks were freed -- no leaks are possible", which is some comfort!)

P.S. Using g++ 4.8.1, on Linux.

UPDATE: explanation of why free() wants a non-const pointer is here: Unable to free const pointers in C (though I found barak manos's answer below clearer on that).

like image 383
Darren Cook Avatar asked May 09 '14 09:05

Darren Cook


People also ask

What is const void * in C?

const void is a type which you can form a pointer to. It's similar to a normal void pointer, but conversions work differently. For example, a const int* cannot be implicitly converted to a void* , but it can be implicitly converted to a const void* .

Can I delete a const pointer?

E2158 Operand of 'delete' must be non-const pointer (C++) It is illegal to delete a variable that is not a pointer. It is also illegal to delete a pointer to a constant.


1 Answers

const_cast can only remove const and volatile qualifiers; it can't change the pointer type. Conversely, static_cast can change the type, but can't remove top-level qualifiers. However, conversion to void* from a non-const object pointer type is implicit, so this should work:

free( const_cast<const char**>(names) );

More tricky conversions, would require both a const_cast and a static_cast (or even reinterpret_cast in weird cases).

The evil C cast can combine both const_cast and static_cast, so could be used as a shortcut for both. However, that's a bad idea since it's more dangerous: if you specify the wrong type, then it will force the conversion via reinterpret_cast, potentially causing weird runtime behaviour where safer casts would fail at compile time.

However, there's no need for any cast here: the conversion from X* to X const* can be done implicitly, so just change the type of the local pointer:

const char ** names = static_cast<const char **>(malloc( sizeof(char*) * cnt));
the_c_function(names); // OK - adds const
free(names);           // OK - no const to remove

Finally, since this is C++, there's no need to muck around with malloc and pointers at all (unless the C API is evil enough to require that it be given memory from malloc):

std::vector<const char*> names(cnt);
the_c_function(names.data());
like image 131
Mike Seymour Avatar answered Oct 19 '22 22:10

Mike Seymour