Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static_cast void* char* vs static_cast void** char**

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?

like image 675
e244 Avatar asked Apr 29 '13 14:04

e244


People also ask

Can you static_cast to void *?

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.

What does static_cast void do?

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.

Is static_cast backwards compatible with C?

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.

What static_cast is actually doing?

static_cast can be used to convert between pointers to related classes (up or down the inheritance hierarchy). It can also perform implicit conversions.


2 Answers

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...)

like image 173
Mats Petersson Avatar answered Oct 15 '22 22:10

Mats Petersson


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**...).

like image 25
David Rodríguez - dribeas Avatar answered Oct 15 '22 23:10

David Rodríguez - dribeas