Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What value does const void * offer over void *?

In C++, is there any value in using a const void * for an argument type to a function over a void *? Since a void * is opaque, is there any risk of modification other than if the user does reinterpret_cast, in which case they could likewise do const_cast on a const void * and thus does one really buy anything? I ask because I was using a utility template class for shared pointers which provided a specialization on void to avoid void & issue but no specialization was provided for const void and thus I wonder whether this was just an oversight or should it never be needed?

like image 951
WilliamKF Avatar asked Jul 09 '12 15:07

WilliamKF


2 Answers

It offers the same benefit that const offers on other pointer types: you can't modify what is pointed to unless you cast away the const-ness explicitly. In interfaces, const void* is a sign to client code that whatever you pass in may be read but not written to. E.g., std::memcpy is declared as

void *memcpy(void *dest, const void *src, std::size_t count);

which signals that it will read src and write to dest. Of course, if it were really implemented in C++ (possible but not likely), it has to cast both pointers to other types.

If you feel that this "doesn't buy you anything", then it's the const keyword per se that apparently has no value.

like image 173
Fred Foo Avatar answered Nov 09 '22 04:11

Fred Foo


memcpy takes two pointer parameters, one void* and the other const void*. The second parameter can be implicitly converted from a const char* (or other pointer-to-const-object-type) argument, whereas the first one can't.

That absence of implicit conversion is the value -- it forces the user to deliberately cast away const in the (unlikely) event that they want to, rather than accidentally discarding it.

Then within an implementation of memcpy, or a similar function, the programmer would have to const_cast or C-style-cast the const void* parameter before attempting to modify its referand. They would be able to static_cast the non-const parameter and modify its referand. The kind of cast you need to write hopefully tells you something about whether what you're doing is sensible.

I think that if your shared_ptr helper functions need to treat void specially, then they would need to treat all cv-qualified void specially. So that's four cases: void, const void, volatile void, const volatile void. But if users of the functions have in the past tried it on a shared_ptr<void>, and complained that it didn't work, but have never tried it on a shared_ptr<const void>, then maybe the issue hasn't arisen.

Maybe shared_ptr<void> is already unusual enough that it hasn't come up. Maybe the kind of person who uses a shared_ptr<void> tends not to mind casting away cv-qualifiers, on the basis that whenever someone eventually restores the correct type, they will also restore the correct qualifiers.

Come to think of it -- does shared_ptr<const void> work at all, or does the code in shared_ptr that calls the deleter need an implicit conversion from T* to void*? I don't rememember whether I've ever used a shared_ptr<const T>.

like image 42
Steve Jessop Avatar answered Nov 09 '22 03:11

Steve Jessop