Is there a legal use for void *?

Is there a legal use of void* in C ++? Or was it introduced because C had it?

Just to remember my thoughts:

Input If we want to allow several types of input, we can overload functions and methods, as an alternative we can define a common base class or template (thanks for mentioning this in the answers). In both cases, the code becomes more descriptive and less error prone (provided that the base class is implemented in a reasonable way).

Conclusion I cannot imagine a situation in which I would prefer to get void* rather than something derived from a well-known base class.

Just to understand what I mean: I am not asking if there is a use case for void* , but if there is a case where void* is the best or only affordable choice. To which perfectly answered a few people below.

+86
c ++
Dec 14 '15 at 17:07
source share
9 answers

void* is at least necessary as a result of ::operator new (also each operator new ...) and malloc and as an argument to the new placement operator.

void* can be considered as a common supertype of each type of pointer. So this does not quite mean a pointer to void , but a pointer to something.

By the way, if you want to save some data for several unrelated global variables, you can use some std::map<void*,int> score; and then declaring global int x; and double y; and std::string s; do score[&x]=1; and score[&y]=2; and score[&z]=3;

memset requires the address void* (the most common)

In addition, POSIX systems have dlsym , and its return type should obviously be void*

+80
Dec 14 '15 at 17:11
source share

There are several reasons to use void* , the 3 most common types:

  • interacts with the C library using void* in its interface
  • type of erase
  • to indicate non-printable memory

In the reverse order, designating non-printable memory with void* (3) instead of char* (or options) helps prevent accidental pointer arithmetic; very few operations are available on void* , so casting is usually required to use them. And of course, very similar to char* there is no problem with aliasing.

Erase type (2) is still used in C ++ in combination with templates or not:

  • non-generic code helps reduce binary bloat, it is useful in cold paths even in generic code
  • non-generic code is sometimes needed for storage even in a universal container such as std::function

And, obviously, when the interface you're working with uses void* (1), you have little choice.

+28
Dec 14 '15 at 18:50
source share

Oh yeah. Even in C ++, sometimes we encounter void * rather than template<class T*> , because sometimes the extra code from the template extension is too large.

Normally, I would use it as the actual implementation of the type, and the type of the template would inherit from it and complete the casts.

In addition, custom slab allocators (new operator implementations) should use void * . This is one of the reasons why g ++ added the extension of the allowable arithmetic pointer to void * , as if it had a size of 1.

+15
Dec 14 '15 at 17:12
source share

Input: if we want to allow several types of input, we can overload functions and methods

True

alternatively we can define a common base class.

This is partly true: what if you cannot define a common base class, interface, or the like? To determine which ones you need to access the source code, which is often not possible.

You did not specify patterns. However, templates cannot help you with polymorphism: they work with static types, that is, they are known at compile time.

void* can be considered the lowest common denominator. In C ++, you usually don’t need it, because (i) you cannot essentially do much with it, and (ii) there are almost always better solutions.

In addition, you should usually convert it to other specific types. This is why char * usually better, although this may indicate that you are expecting a C-style string rather than a clean data block. For this, void* better than char* for this, because it allows for implicit casting from other types of pointers.

You should receive some data, work with it and make a conclusion; To achieve this, you need to know the data you are working with, otherwise you have another problem that is not the one you originally solved. In many languages ​​there is no void* and, for example, there is no problem with this.

Other legal use

When printing pointer addresses with functions such as printf , the pointer must be of type void* and therefore you may need to cast to void *

+10
Dec 14 '15 at 17:22
source share

Yes, it is as useful as any other thing in this language.
As an example, you can use it to erase a class type, which, if necessary, can be statically applied in the desired type to have a minimal and flexible interface.

Which answers, there is an example of use that should give you an idea.
I will copy and paste it below for 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 tasks of using void* .

+7
Dec 14 '15 at 17:32
source share

Interaction with an external library function that returns a pointer. Here is one of the Ada apps.

 extern "C" { void* ada_function();} void* m_status_ptr = ada_function(); 

This returns a pointer to what Ada wanted to tell. You do not need to do anything with this, you can return it to Ada to do the following. In fact, unraveling the Ada pointer in C ++ is non-trivial.

+3
Dec 15 '15 at 12:45
source share

In short, C ++ as a strict language (not taking into account C relics such as malloc ()) requires void * because it does not have a common parent of all possible types. Unlike ObjC, for example, which has an object.

+2
Dec 14 '15 at 20:34
source share

The first thing that comes to my mind (I suspect this is a specific case from the pair of answers above) is the ability to pass an instance of an object to a thread in Windows.

I have several C ++ classes that need to do this, they have workflow implementations, and the LPVOID parameter in the CreateThread () API gets the address of the implementation of the static method in the class so that the workflow can work with a specific instance of the class. A simple static return to threadproc gives the instance to work, allowing each instance instance to have a worker thread from one static method implementation.

+1
Dec 16 '15 at 9:22
source share

In the case of multiple inheritance, if you need to get a pointer to the first byte of the memory block occupied by the object, you can dynamic_cast to void* .

0
Dec 31 '15 at 14:21
source share



All Articles