简体   繁体   中英

Why can't static_cast a double void pointer?

Consider the following piece of code:

void **v_dptr(nullptr);
int  **i_dptr = static_cast<int**>(v_dptr);

The above example produces the following compile error:

static_cast from 'void **' to 'int **' is not allowed

LIVE DEMO

I know that the proper way to cast a void pointer to any other pointer type is to use static_cast . However, you can't static_cast a double void pointer to another double pointer of other type.

Q:

  1. Why we can't static_cast a double void pointer?
  2. What's the proper way to cast a double void pointer?

When you have a void* and cast it to an int* , there may or may not be some mathematical/width adjustment to create an instance of the proper type, which static_cast<> will be prepared to do. When you have only a pointer to a void* and want a pointer to an int* , the static_cast<> has no write access to the pointed-to void* object; it is not free to adjust it to make sure it's a valid int* such that the static_cast<> can succeed and return a pointer which really can be used to access a valid int* . While on some architectures this may not matter, if the standard allowed this then the code could break when ported. (Keep in mind that it's unreasonable to expect the static_cast<> to arrange for some additional memory for an int* somewhere that it initialises using a static_cast<int*>(the_void_ptr) - not only would that have unexpected overheads, but it'd need to be in thread specific memory or allocated dynamically and released somehow, and all manner of code that actually ends up comparing the pointer values would break.)

If you want to force the matter and promise the compiler that the width of both types is the same and no mathematical adjustment is necessary etc. - then you can use reinterpret_cast<> and boss it around, making it clear you're accepting the risk of undefined behaviour.

void* is special in that it can point to anything. It is a "pointer to unspecified type." Therefore, converting to and from void* to T* for some type T is a "normal" operation, one which static_cast can support. In effect, such a conversion says: "The pointer doesn't know to what it points, but I know it: it points to a T ."

void** is not special special in this way. It can point to one thing only, to a void* . Converting a void** to an int** says something different: "The pointer claims it points to a void* , but I want to treat it as a pointer to int* instead." And if you want to treat one thing as a different thing, you want to reinterpret the original - so use reinterpret_cast .

I believe this is an XY-problem. Depending on the circumstances it can be solved without reinterpret_cast . If you know that the void** pointer in fact points to a pointer to int , you can safely do this:

int* iptr = static_cast<int*>(*v_dptr);

Unless you really need int** in your code. And if you need, you can do:

int** i_dptr = &iptr;

but beware that it will point to a local variable iptr which will be destroyed when goes out of scope.

There are good answers for Q1, and the answer to Q2 depends a lot on the intention. If void **v_dptr is intended to be a pointer to a "generic" void* which you know is actually a int* and you want to cast accordingly, the following might be what you want:

int *i_ptr = static_cast<int*>(*v_dptr);
int **i_dptr = &i_ptr;

A static_cast can do the reverse of any implicit conversion.

There is an implicit conversion int*void* ; it doesn't do more than lose the information about the type of the pointed to object.

There is no implicit conversion int**void** . If it was allowed it would reinterpret the object pointer to, namely, reinterpreting an int* as a void* . On some old architectures an int* did not necessarily have as large a value representation as a void* (or char* , the pointer types with the least alignment requirements).

The reinterpretation requires a reinterpret_cast .

IMHO it's a good idea to use reinterpret_cast in general for conversions to/from void* , because that communicates intent to the reader. However, as I recall Sutter and Alexandrescu recommended using static_cast , presumably due to a lack of a formal guarantee in C++03. Also as I recall, that purely formal problem was fixed in C++11.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM