If I do the following all is ok:
char* cp = "abc";
void* vp = NULL;
vp = static_cast<void*>(cp);//ok
cp = static_cast<char*>(vp);//ok
But the following is not:
char** cpp = &cp;
void** vpp = NULL;
vpp = static_cast<void**>(cpp);//error C2440: 'static_cast':
//cannot convert from 'char **' to 'void **'
cpp = static_cast<char**>(vpp);//error C2440: 'static_cast':
//cannot convert from 'void **' to 'char **'
Please can someone explain to me why the second examples are not allowed. Please don't quote the C++ standard as your whole answer, because I've already seen answers that quote it, and I don't understand what they meant. I want to understand why the second examples don't work (ie. if you could give an example where it would be dangerous that would be a great help). Because I don't get it. To me, both examples are casting pointers. Why does an additional level of indirection make any difference?
The static_cast operator converts a null pointer value to the null pointer value of the destination type. Any expression can be explicitly converted to type void by the static_cast operator.
If, in your code, you know you do not need a result somewhere, you can use the static_cast<void> method to mark the result as discarded – but the compiler will consider the variable used then and no longer create a warning or error.
Since C++ is 99% backwards-compatible with C, most C source code can be compiled as C++ source code and will work, and in that scenario, static_cast could be part of the code and would compile.
static_cast can be used to convert between pointers to related classes (up or down the inheritance hierarchy). It can also perform implicit conversions.
A void *
pointer can point at "anything", and it is valid to convert all pointers to a void *
, and it is valid to convert all pointers from void *
to some other type.
However, a void **
is a pointer that points to a void *
value. And a char **
is a pointer that points to char *
value. These types don't point to the types that are convertible from one another. You can, if you NEED to do this, use void **vpp = reinterpret_cast<void **>(cpp);
, but it's "not safe" (you are basically telling the compiler "Look, I know what I'm doing here, so just do it", which may not do what you actually expected...)
The restriction is to avoid breaking the type system. The first conversion is fine:
type *p = ...;
void *vp = p;
While you are giving away the type, you cannot inflict too much damage to the original value without since there is little to be done with a void
object and all changes to vp
are local to the pointer and cannot affect p
.
If the second case was allowed:
type **p = ...;
void **vp = p;
Then perfectly looking and correct code could break your application. For example:
int *parray[10];
int **p = parray;
void **vp = p;
*vp = new double(); // now parray[0] is a pointer to a double object,
// not a pointer to an int!!!
The type system has been subverted.
That is, the problem is that in the second case there are operations that can be applied to the destination pointer that can modify the original object and cause bugs. Similar examples can be found with const
other cases (you can convert int*
to const int*
, but you cannot convert int**
to const int**
...).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With