Is there a legitimate use for void*?
C++C++ Problem Overview
Is there a legitimate use of void*
in C++? Or was this introduced because C had it?
Just to recap my thoughts:
Input: If we want to allow multiple input types we can overload functions and methods, alternatively we can define a common base class, or template (thanks for mentioning this in the answers). In both cases the code get's more descriptive and less error prone (provided the base class is implemented in a sane way).
Output: I can't think of any situation where I would prefer to receive void*
as opposed to something derived from a known base class.
Just to make it clear what I mean: I'm not specifically asking if there is a use-case for void*
, but if there is a case where void*
is the best or only available choice. Which has been perfectly answered by several people below.
C++ Solutions
Solution 1 - C++
void*
is at least necessary as the result of ::operator new
(also every operator new
...) and of malloc
and as the argument of the placement new
operator.
void*
can be thought as the common supertype of every pointer type. So it is not exactly meaning pointer to void
, but pointer to anything.
BTW, if you wanted to keep some data for several unrelated global variables, you might use some std::map<void*,int> score;
then, after having declared global int x;
and double y;
and std::string s;
do score[&x]=1;
and score[&y]=2;
and score[&z]=3;
memset
wants a void*
address (the most generic ones)
Also, POSIX systems have dlsym and its return type evidently should be void*
Solution 2 - C++
There are multiple reasons to use void*
, the 3 most common being:
- interacting with a C library using
void*
in its interface - type-erasure
- denoting un-typed memory
In reverse order, denoting un-typed memory with void*
(3) instead of char*
(or variants) helps preventing accidental pointer arithmetic; there are very few operations available on void*
so it usually require casting before being useful. And of course, much like with char*
there is no issue with aliasing.
Type-erasure (2) is still used in C++, in conjunction with templates or not:
- non-generic code helps reducing binary bloat, it's useful in cold paths even in generic code
- non-generic code is necessary for storage sometimes, even in generic container such as
std::function
And obviously, when the interface you deal with uses void*
(1), you have little choice.
Solution 3 - C++
Oh yes. Even in C++ sometimes we go with void *
rather than template<class T*>
because sometimes the extra code from the template expansion weighs too much.
Commonly I would use it as the actual implementation of the type, and the template
Also, custom slab allocators (operator new implementations) must use void *
. This is one of the reasons why g++ added an extension of permitting pointer arithmatic on void *
as though it were of size 1.
Solution 4 - C++
> Input: If we want to allow multiple input types we can overload > functions and methods
True. >alternatively we can define a common base > class.
This is partially true: what if you can't define a common base class, an interface or similar? To define those you need to have access to the source code, which is often not possible.
You didn't mention templates. However, templates cannot help you with polymorphism: they work with static types i.e. known at compile time.
void*
may be consider as the lowest common denominator. In C++, you typically don't need it because (i) you can't inherently do much with it and (ii) there are almost always better solutions.
Even further, you will typically end up on converting it to other concrete types. That's why char *
is usually better, although it may indicate that you're expecting a C-style string, rather than a pure block of data. That's whyvoid*
is better than char*
for that, because it allows implicit cast from other pointer types.
You're supposed to receive some data, work with it and produce an output; to achieve that, you need to know the data you're working with, otherwise you have a different problem which is not the one you were originally solving. Many languages don't have void*
and have no problem with that, for instance.
Another legitimate use
When printing pointer addresses with functions like printf
the pointer shall have void*
type and, therefore, you may need a cast to void
*
Solution 5 - C++
Yes, it is as useful as any other thing in the language.
As an example, you can use it to erase the type of a class that you are able to statically cast to the right type when needed, in order to have a minimal and flexible interface.
In that response there is an example of use that should give you an idea.
I copy and paste it below for the sake of clarity:
class Dispatcher {
Dispatcher() { }
template<class C, void(C::*M)() = C::receive>
static void invoke(void *instance) {
(static_cast<C*>(instance)->*M)();
}
public:
template<class C, void(C::*M)() = &C::receive>
static Dispatcher create(C *instance) {
Dispatcher d;
d.fn = &invoke<C, M>;
d.instance = instance;
return d;
}
void operator()() {
(fn)(instance);
}
private:
using Fn = void(*)(void *);
Fn fn;
void *instance;
};
Obviously, this is only one of the bunch of uses of void*
.
Solution 6 - C++
Interfacing with an external library function which returns a pointer. Here is one for an Ada application.
extern "C" { void* ada_function();}
void* m_status_ptr = ada_function();
This returns a pointer to whatever it was Ada wanted to tell you about. You don't have to do anything fancy with it, you can give it back to Ada to do the next thing. In fact disentangling an Ada pointer in C++ is non-trivial.
Solution 7 - C++
In short, C++ as a strict language (not taking into account C relics like malloc()) requires void* since it has no common parent of all possible types. Unlike ObjC, for example, which has object.
Solution 8 - C++
The first thing that occurs to my mind (which I suspect is a concrete case of a couple of the answers above) is the capability to pass an object instance to a threadproc in Windows.
I've got a couple of C++ classes which need to do this, they have worker thread implementations and the LPVOID parameter in the CreateThread() API gets an address of a static method implementation in the class so the worker thread can do the work with a specific instance of the class. Simple static cast back in the threadproc yields the instance to work with, allowing each instantiated object to have a worker thread from a single static method implementation.
Solution 9 - C++
In case of multiple inheritance, if you need to get a pointer to the first byte of a memory chunk occupied by an object, you may dynamic_cast
to void*
.