Dovrei usare static_cast o reinterpret_cast quando lancio un vuoto * a qualunque cosa


202

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?


78
@anon Apparentemente non hai mai lavorato con i thread POSIX prima di allora.
user470379,

7
@ user470379 Wow ... questa è la vera ragione per cui sono arrivato a questa domanda a SO! Ottima osservazione :-).
Ogre Salmo33,

Risposte:


148

Usastatic_cast : è il cast più stretto che descrive esattamente quale conversione viene fatta qui.

C'è un malinteso sul fatto che l'uso reinterpret_castsarebbe 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_castha 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.


8

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.


6
" operatore diverso per designare solo reinterpretazioni puntatore (che ha garantito lo stesso indirizzo restituito) " Abbraccio? Quell'operatore è reinterpret_cast !
curiousguy,

2
@curiousguy Non vero secondo lo standard. reinterpret_cast NON garantisce che venga utilizzato lo stesso indirizzo. Solo che se reinterpret_cast da un tipo all'altro e poi di nuovo indietro , otterrai lo stesso indirizzo con cui hai iniziato.
ClydeTheGhost

0

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.


2
" reinterpret_cast può essere usato per lanciare un puntatore su un float. " Certamente no!
curiousguy,

3
Probabilmentefloat f = *reinterpret_cast<const float*>(&p);
Ben Voigt,

2
@BenVoigt Questo è il casting tra puntatori; uno di loro era un puntatore a virgola mobile.
nodakai,

5
@BenVoigt "l'espressione intera" non è un cast però. L'espressione consiste in una dereferenza applicata a un cast. Hai affermato che era possibile lanciare un puntatore a 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.
MM

2
@BenVoigt hai offerto quel codice in risposta a qualcuno che chiedeva "Come faccio a lanciare ...", e poi quando qualcuno ha detto che il codice viene lanciato tra i puntatori (cosa che fa), hai detto "No"
MM

-7

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.