33

In C, there is no need to cast a void * to any other pointer type, it is always safely promoted. However, in C++, this is not the case. E.g.,

int *a = malloc(sizeof(int));

works in C, but not in C++. (Note: I know that you shouldn't use malloc in C++, or for that matter new, and should instead prefer smart pointers and/or the STL; this is asked purely out of curiosity) Why does the C++ standard not allow this implicit cast, while the C standard does?

Kilian Foth
  • 110,899

4 Answers4

39

Because implicit type conversions are usually unsafe, and C++ takes a more safe stance to typing than C does.

C will usually allow implicit conversions, even if most chances are that the conversion is an error. That's because C assumes that the programmer knows exactly what they are doing, and if not, it is the programmer's problem, not the compiler's problem.

C++ will usually disallow things that could potentially be errors, and require you to explicitly state your intention with a type cast. That's because C++ is trying to be programmer-friendly.

You might ask how come it is friendly when it is actually requiring you to type more.

Well, you see, any given line of code, in any program, in any programming language, will generally be read many more times than it will be written (*). So, ease of reading is much more important than ease of writing. And when reading, having any potentially unsafe conversions stand out by means of explicit type casts helps to understand what is going on and to have a certain level of certainty that what is happening is in fact what was intended to happen.

Besides, the inconvenience of having to type the explicit cast is trivial compared to the inconvenience of hours upon hours of troubleshooting to find a bug which was caused by a mistaken assignment that you could have been warned about, but never were.

(*) Ideally it will be written only once, but it will be read every time someone needs to review it to determine its suitability for reuse, and every time there is troubleshooting going on, and every time someone needs to add code near it, and then every time there is troubleshooting of nearby code, and so on. This is true in all cases except for "write-once, run, then throw away" scripts, and so it is no wonder that most scripting languages have a syntax which facilitates ease of writing with complete disregard to ease of reading. Ever thought that perl is completely incomprehensible? You are not alone. Think of such languages as "write-only" languages.

Mike Nakis
  • 32,803
30

Here is what Stroustrup says:

In C, you can implicitly convert a void* to a T*. This is unsafe

He then goes on to show an example of how void* can be dangerous and says:

... Consequently, in C++, to get a T* from a void* you need an explicit cast. ...

Finally, he notes:

One of the most common uses of this unsafe conversion in C is to assign the result of malloc() to a suitable pointer. For example:

int* p = malloc(sizeof(int));

In C++, use the typesafe new operator:

int* p = new int;

He goes into a lot more detail on this in The Design and Evolution of C++.

So the answer boils down to: The language designer believes it is an unsafe pattern, and so made it illegal and provided alternate ways of accomplishing what the pattern was normally used for.

10

In C, there is no need to cast a void * to any other pointer type, it is always safely promoted.

It's always promoted, yes, but hardly safely.

C++ disables this behaviour precisely because it attempts to have a safer type system than C, and this behaviour is not safe.


Consider in general these 3 approaches to type conversion:

  1. force the user to write everything out, so all conversions are explicit
  2. assume the user knows what they're doing and convert any type to any other
  3. implement a complete type system with type-safe generics (templates, new-expressions), explicit user-defined conversion operators, and force explicit conversions only of things the compiler can't see are implicitly safe

Well, 1 is ugly and a practical obstacle to getting anything done, but might genuinely be used where great care is needed. C roughly opted for 2, which is easier to implement, and C++ for 3, which is harder to implement but safer.

Useless
  • 12,823
2

By definition, A void pointer can point to anything. Any pointer can be converted to a void pointer and thus, you will be able to convert back arriving at the exact same value. However, pointers to other types may have constraints, such as alignment restrictions. For example, imagine an architecture where characters can occupy any memory address but integers must start on even address boundaries. In certain architectures, integer pointers might even count 16, 32 or 64 bits at a time so that a char * might actually have a multiple of the numeric value of int * while pointing to the same place in memory. In this case, converting from a void * actually would round off bits which can not be recovered and is therefore not reversible.

Put simply, the void pointer can point to anything, including things that other pointers may not be capable of pointing to. Thus, the conversion to the void pointer is safe but not the other way around.

roserez
  • 29