Sia static_cast che reinterpret_cast sembrano funzionare bene per lanciare void * su un altro tipo di puntatore. C'è una buona ragione per favorire l'uno rispetto all'altro?
Sia static_cast che reinterpret_cast sembrano funzionare bene per lanciare void * su un altro tipo di puntatore. C'è una buona ragione per favorire l'uno rispetto all'altro?
Risposte:
Usastatic_cast
: è il cast più stretto che descrive esattamente quale conversione viene fatta qui.
C'è un malinteso sul fatto che l'uso reinterpret_cast
sarebbe una corrispondenza migliore perché significa "ignorare completamente la sicurezza del tipo e lanciare da A a B".
Tuttavia, questo in realtà non descrive l'effetto di a reinterpret_cast
. Piuttosto, reinterpret_cast
ha un certo numero di significati, per tutti i quali sostiene che "la mappatura eseguita da reinterpret_cast
è definita dall'implementazione". [5.2.10.3]
Ma nel caso particolare del casting da void*
aT*
mappatura è completamente ben definita dallo standard; vale a dire, assegnare un tipo a un puntatore senza tipo senza modificarne l'indirizzo.
Questo è un motivo per preferire static_cast
.
Inoltre, e probabilmente più importante, è il fatto che ogni uso reinterpret_cast
è decisamente pericoloso perché converte qualsiasi cosa in qualsiasi altra cosa (per i puntatori), mentre static_cast
è molto più restrittivo, fornendo così un livello di protezione migliore. Questo mi ha già salvato da bug in cui ho accidentalmente cercato di forzare un tipo di puntatore in un altro.
Questa è una domanda difficile. Da un lato, Konrad sottolinea in modo eccellente la definizione delle specifiche per reinterpret_cast , anche se in pratica probabilmente fa la stessa cosa. D'altra parte, se stai eseguendo il casting tra tipi di puntatore (come è abbastanza comune quando si indicizza in memoria tramite un carattere *, ad esempio), static_cast genererà un errore del compilatore e sarai comunque costretto a utilizzare reinterpret_cast .
In pratica uso reinterpret_cast perché è più descrittivo dell'intento dell'operazione cast. Si potrebbe certamente chiedere a un operatore diverso di designare solo reinterpretazioni del puntatore (che ha garantito lo stesso indirizzo restituito), ma non ce n'è uno nello standard.
reinterpret_cast
!
Suggerisco di usare sempre il cast più debole possibile.
reinterpret_cast
può essere usato per lanciare un puntatore a float
. Più il cast viene distrutto dalla struttura, maggiore è la sua attenzione.
Nel caso char*
, userei il cast in stile c, fino a quando non ne avremo alcuni reinterpret_pointer_cast
, perché è più debole e nient'altro è sufficiente.
float f = *reinterpret_cast<const float*>(&p);
float
, il che è falso. I calchi di espressione void **
per const float *
e quindi utilizza un'operazione di dereference (che non è un cast), per la conversione const float *
a float
.
Le mie preferenze personali si basano sull'alfabetizzazione del codice in questo modo:
void* data = something;
MyClass* foo = reinterpret_cast<MyClass*>(data);
foo->bar();
o
typedef void* hMyClass; //typedef as a handle or reference
hMyClass = something;
const MyClass& foo = static_cast<MyClass&>(*hMyClass);
foo.bar();
Entrambi fanno lo stesso alla fine, ma static_cast sembra più appropriato in un ambiente di app di livello intermedio, mentre reinterpretare il cast sembra più simile a qualcosa che vedresti in una libreria di livello inferiore IMHO.