Domanda

Ho bisogno di convertire un tipo integrale che contiene un indirizzo per il tipo di puntatore effettivo. Potrei usare reinterpret_cast come segue:

MyClass *mc1 = reinterpret_cast<MyClass*>(the_integer);

Tuttavia, questo non effettua alcun controllo in fase di esecuzione per vedere se l'indirizzo in questione contiene in realtà un oggetto MyClass. Voglio sapere se c'è qualche beneficio in prima conversione a un void * (utilizzando reinterpret_cast) e quindi utilizzando dynamic_cast sul risultato. In questo modo:

void *p = reinterpret_cast<void*>(the_integer);
MyClass *mc1 = dynamic_cast<MyClass*>(p);
assert(mc1 != NULL);

C'è qualche vantaggio nell'uso del secondo metodo?

È stato utile?

Soluzione

il controllo di tipo on dynamic_cast è implementata in modo diverso da diverse implementazioni C ++; se si desidera una risposta per la vostra specifica implementazione si dovrebbe parlare di quello implementazione che si sta utilizzando. L'unico modo per rispondere alla domanda, in generale, è quello di fare riferimento alla ISO ++ C standard.

Con la mia lettura della norma, chiamando dynamic_cast su un puntatore nullo è illegale:

dynamic_cast<T>(v)
  

"Se T è un tipo di puntatore, V è un rvalue di un puntatore per completare tipo di classe"

(da 5.2.7.2 della norma ISO C ++). void non è un tipo di classe completo, quindi l'espressione è illegale.

È interessante notare che il tipo di essere gettato a è permesso di essere un puntatore nullo, cioè.

void * foo = dynamic_cast<void *>(some_pointer);

In questo caso, il dynamic_cast riesce sempre, ed il valore risultante è un puntatore all'oggetto più derivato puntato da v.

Altri suggerimenti

No, non c'è alcun vantaggio specifico nel farlo. Nel momento in cui si utilizza reinterpret_cast, tutte le scommesse sono spenti. E 'a voi per essere sicuri che il cast è valido.

In realtà nessun serio vantaggio. Se il vuoto * punti a qualcosa che non è un puntatore ad un oggetto polimorfico si esegue in un comportamento indefinito (di solito una violazione di accesso) immediatamente.

Il modo più sicuro è quello di tenere un registro di tutti gli oggetti MyClass dal vivo. E 'meglio per mantenere questo record in un std::set<void*>, il che significa che si può facilmente aggiungere, rimuovere e gli elementi di prova.

La ragione per la loro memorizzazione come void*s è che non si rischia nastyness come la creazione di puntatori MyClass* non allineati dai vostri numeri interi.

  • Prima di tutto "reinterpretare" int a void * è una cattiva idea. Se sizeof(int) è 4 e sizeof(void *) è di 8 (64x del sistema) è mal-formata.

  • Inoltre dynamic_cast è valido solo per il caso delle classi polimorfiche.

L'opzione 1 è il tuo unico (semi) portatile opzione / valido.

Opzione 2: non è valido C ++ come il dynamic_cast (come void non è consentito)

.

A livello di attuazione che richiede le informazioni sul tipo dal tipo di origine per raggiungere il tipo di destinazione. Non esiste un modo (o non ci può essere alcun modo) per ottenere le informazioni di tipo di origine di runtime da un void * quindi questo non è valido sia.

dynamic_cast viene utilizzato per CAS su e giù per la gerarchia di tipo non dai tipi sconosciuti.

Come un lato nota probabilmente si dovrebbe utilizzare void * piuttosto che un intero per memorizzare un puntatore non tipizzato. Esiste la possibilità di un int non essere abbastanza grande per memorizzare un puntatore.

Il modo più sicuro per gestire i puntatori in C ++ è di gestirli typesafe. Ciò significa:

  • Mai puntatori negozio in altro che un puntatore
  • Evita puntatori void
  • Mai passare puntatori ad altri processi
  • considerare weak_ptr se si prevede di utilizzare i puntatori sopra le discussioni

La ragione di questo è: che cosa avete intenzione di fare non è sicuro e può essere evitato a meno che non si sta interfacciamento con codice non sicuro (legacy?). In questo caso, prendere in considerazione la risposta MSalters', ma essere consapevoli del fatto che è ancora una seccatura.

Se si sa per certo che i punti the_integer ad una classe di base noto (che ha almeno un membro virtuale), ci potrebbe in realtà essere un vantaggio: sapendo che l'oggetto è di una specifica classe derivata. Ma dovreste reinterpret_cast alla classe di base e poi fai la dynamic_cast:

BaseClass* obj = reinterpret_cast<BaseClass*>(the_integer);
MyClass* myObj = dynamic_cast<BaseClass*>(obj);

Utilizzo di un void* in dynamic_cast è inutile e semplicemente sbagliato. Non è possibile utilizzare dynamic_cast per verificare se c'è un oggetto valido in qualche posizione arbitraria nella memoria.

Si dovrebbe anche prestare attenzione quando si ripone indirizzi in variabili di tipo non-puntatore. Ci sono architetture dove sizeof (void *)! = Sizeof (int), ad esempio LP64.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top