Casting Between Pointer Types
In C, a void* may be assigned to a pointer of any type without a cast; in C++ this implicit conversion is not allowed.
A Porting Trap
A pointer assignment can look ordinary in C and still fail when the same code is compiled as C++. The key difference is how the two languages treat a conversion from void* to a pointer to a specific type.
What do you think happens?
Suppose ch is a character variable and raw points to ch through a void*. In C++, will this assignment be accepted without a cast?
Reveal answer
No. C++ does not allow assigning raw, a void*, to an int* without an explicit conversion.
C permits this assignment without a cast; C++ does not. The fact that the assignment is accepted in C does not make the converted pointer safe to use for accessing the object.
When a Pointer Type Misleads
A void* can point to an object of any type, but the void* itself does not say what type of object is at that address. Converting it to another pointer type makes the program treat that memory as though it were an object of the new type. If the new type is larger than the object actually stored there, writing through the converted pointer can reach neighboring bytes that belong to something else.
- The assignment from void* to int* is accepted in C but not in C++ without a cast.
- The write illustrates the danger of treating the character object's storage as an int object.
Reviewing C Code in C++
When C code is moved into a C++ project, look for assignments that implicitly convert void* to another pointer type. Make each conversion explicit so its intended target type is visible for review. The source also notes that malloc() returns void*: in C++ its result must be cast to the right pointer type. For code that is C++ only, the guidance is to avoid malloc().
- The cast makes the intended pointer type explicit for a
malloc()result.
Testing a dynamic_cast Result
A pointer-form dynamic_cast attempts to produce a pointer to the requested type. For example, requesting a Smiley* from ps checks whether the pointed-to object is a Smiley or belongs to a class derived from Smiley. If it is neither, the result is nullptr. Treat the result as something to test before using it as a pointer to the requested type.
- The cast result is stored in p.
- The condition checks that the result is not nullptr before the matching case uses p.
Practice the Decision
For each case, predict the result before reading the hints: (1) In C++, raw is a void* and p is an int*. Is p = raw accepted without a cast? (2) A pointer-form dynamic_cast requests Smiley*, and the pointed-to object is of a class derived from Smiley. What does the cast produce? (3) The cast result is nullptr. Should the program use it as a pointer to a matching Smiley object?
Hints
- C++ does not allow the implicit void* to typed-pointer conversion.
- A pointer-form
dynamic_castsucceeds for the requested type or an object of a class derived from it. - Check the result before using it; nullptr signals that the requested type did not match.
Common mistake Assuming a void* assignment accepted in C is also accepted in C++.
What it looks likeint* p = raw; where raw has type void*.Why it failsC++ does not allow this implicit conversion.
Do this insteadWhen reviewing C code moved to C++, make the intended conversion explicit.
Common mistake Assuming a converted pointer proves that the memory contains an object of the new type.
What it looks likeWriting through an int* that was obtained from a void* pointing to a character object.
Why it failsThe write can reach neighboring bytes that belong to something else.
Do this insteadDo not treat the conversion alone as evidence that using the new pointer is safe.
Common mistake Using a dynamic_cast result without checking whether it is nullptr.
Why it failsA pointer-form
dynamic_castreturns nullptr when the pointed-to object is not the requested type or a class derived from it.Do this insteadTest the result before using it as a pointer to the requested type.
Keep the Two Checks Distinct
- 1C permits assigning a void* to another pointer type without a cast; C++ does not.
- 2A conversion does not establish that the memory can safely be used as the new type. A write through a mismatched pointer can reach neighboring bytes.
- 3The source guidance is to cast
malloc()results to the right type when usingmalloc()in C++, and to avoidmalloc()in C++-only code. - 4A pointer-form
dynamic_castattempts to produce the requested pointer type. It returns nullptr when the object is neither that type nor derived from it. - 5Check a
dynamic_castresult before using it as a pointer to the requested type.
Key Takeaways
- C accepts an implicit conversion from void* to another pointer type; C++ requires an explicit conversion.
- A pointer conversion can lead to writes reaching memory beyond the intended object.
- Cast
malloc()results to the right pointer type when usingmalloc()in C++, and avoidmalloc()in C++-only code. - A pointer-form
dynamic_castreturns a matching pointer or nullptr. - Test the
dynamic_castresult before using the pointer.