user8132365
user8132365

Reputation:

Why would you convert to a void pointer?

I saw the following code in this question:

class CFoo
{
   int a;
public:
   CFoo():a(1){}
   ~CFoo(){}
   getNum(){return a;}
};

void tfunc(void* data)
{
    CFoo* foo = static_cast<CFoo*>(data);
    std::cout << "Number: " << foo->getNum();
    delete foo;
}

int main()
{
   CFoo* foo = new CFoo;
   void* dt = static_cast<void*>(foo);
   tfunc(dt); // or tfunc(static_cast<void*>(food));

   return 0;
}

and started to wonder about why you would convert a pointer to a type to a pointer to void instead of simply assign the void pointer the the actual pointer. Like when calling tfunc in the code code above, he could have called it like tfunc(&foo) instead of converting the pointer to a type to void pointer as he did using the static cast static_cast<void*>(foo);, right?

Upvotes: 2

Views: 260

Answers (2)

Stephan Lechner
Stephan Lechner

Reputation: 35154

From the example above I do not understand why the signature of function tfunc is void tfunc(void* data) and not void tfunc(class CFoo* data).

Anyway, it is valid to convert a pointer to any type T into a void *, and it is valid to convert such a pointer back to T* later. The conversion from T* can be implicit, whereas conversion from void* back to T* needs to be explicit. So, in your example, tfunc(foo) is equivalent to tfunc(static_cast<void*>(foo)) and to tfunc(dt).

Concerning the point "conversion of CFoo* to void*, there is a standard conversion (cf. this c++ online draft standard):

4 (1) Standard conversions are implicit conversions with built-in meaning. Clause 4 enumerates the full set of such conversions.

4.10 Pointer conversions (2) A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The result of converting a non-null pointer value of a pointer to object type to a “pointer to cv void” represents the address of the same byte in memory as the original pointer value. ...

I'd prefer the implicit conversion over explicit conversions, as the the built-in meaning of the (implicit) standard conversion meets exactly the requirements.

A use case for void* in a function signature could be that one wants to pass objects of unrelated type and decide inside the function to which type it has to be casted back. Suppose, for example, a function handling callbacks for different response types, and each response type might pass different (class hierarchically independent) objects:

void someCallback(int responseType, void *context) {
  if(responseType == 1) {
    CFoo1* foo1 = static_cast<CFoo1*>(context);
    ...
  }
  else {
    CFoo2* foo2 = static_cast<CFoo2*>(context);
    ...
  }
}

Upvotes: 1

bolov
bolov

Reputation: 75688

The wording of your question is a bit confusing, you are not actually asking why converting to void*, you are asking why use explicit casting instead of rely on implicit casting, i.e.

tfunc(static_cast<void*>(food)); // explicit casting

vs

tfunc(food); // implicit casting

The issue is a bit more general than casting to void*. Unfortunately C++ allows a fair amount of implicit dangerous castings. E.g. between singed and unsigned, from a wider integer or floating point to a narrower one, conversions to bool and conversions to void*. All this conversions have the potential to silently introduce bugs in the code. c++11 did a little step in the right direction by not allowing narrowing in the new uniform initializer syntax {}, but due to backward compatibility all previous implicit casts are still allowed.

That's why explicit casting is encouraged. It helps showing the intent of the writer. It shows that the conversion is explicitly desired, as opposed to happening silently, possibly without the author knowledge. Also very important, it helps on code review or when reading the code by being a flag sort of "Here there is cast. Be aware of that when you look over this code"

Upvotes: 2

Related Questions