2015-02-07 16 views
7

In una classe variante sto lavorando stoccaggio crudo è un array di caratteri:reinterpret_cast/static_cast e comportamento indefinito

alignas(/* the strictest alignment of all types of the variant */) 
char storage[/* ... */]; 

L'operatore di assegnazione è qualcosa di simile:

template<class X> 
void operator=(const X &x) 
{ 
    // ...code for clearing the storage and setting the tag for type X... 

    new(storage) X(x); 
} 

mentre il codice per ottenere l'oggetto memorizzato è:

template<class X> 
const X &get() 
{ 
    // ... 
    return *reinterpret_cast<X *>(storage); 
    // ... 
} 

Sembra funzionare ma è sempre ben definito? Sono preoccupato per il dereferenziamento sicuro del puntatore (è consentito dalle regole di tipo aliasing?).

Ci sono delle differenze tra l'implementazione corrente e

return *static_cast<const X *>(static_cast<const void *>(storage)); 

questione connessa/risposta:

https://stackoverflow.com/a/7321815/3235496 (vedi James Kanze 's commenti).


EDIT

Seconda domanda ha già una risposta qui: C++ When should we prefer to use a two chained static_cast over reinterpret_cast

+0

Sicuramente questo 'nuovo (spazio di archiviazione) X (x);' è una perdita di memoria –

+1

@EdHeal Costruisce X nell'archivio tramite il nuovo posizionamento. Dovrebbe essere una pratica sicura per lo storage allineato (ad esempio http://stackoverflow.com/questions/4583125/char-array-as-storage-for-placement-new). Potresti aggiungere qualche dettaglio? – manlio

risposta

4

Come storage è allineato correttamente, non riesco a immaginare dove un problema potrebbe sorgere. Il paragrafo (*) 4.10 sulle conversioni del puntatore dice: Un valore di prvalore di tipo "puntatore a cv T", dove T è un tipo di oggetto, può essere convertito in un valore di tipo "puntatore a cv void". Il risultato della conversione di un puntatore non nullo di un puntatore in un tipo di oggetto in un "puntatore al cv void" rappresenta l'indirizzo dello stesso byte in memoria del valore del puntatore originale.

Per quanto riguarda la seconda domanda, paragrafo 5.2.10 su reinterpres_cast: Un puntatore oggetto può essere esplicitamente convertito in un puntatore oggetto di un tipo diverso. Quando un valore di prvalore v di tipo puntatore oggetto viene convertito nel puntatore oggetto "puntatore a cv T", il risultato è static_cast<cv T*>(static_cast<cv void*>(v)) dove cv corrisponde a const o volatile.

Quindi questa parte è garantita per specifiche. Più come abbiamo visto che un cast di void * deve puntare al primo byte di memoria, non c'è UB per la mia comprensione dei compilatori standard, ... a condizione hanno stessa comprensione ;-)

(*) Référence: Draft for current C++ specification

Problemi correlati