2013-08-19 10 views
11

Nel codice C++ 03, in che modo può implementare un buffer unsigned char[sizeof(T)] con le stesse dimensioni e l'allineamento di un determinato tipo T?Come implementare in modo portabile lo storage stack allineato in C++ 03?

Ad esempio:

template<class T> 
void test() 
{ 
    unsigned char buffer[sizeof(T)]; // <----- how do I ensure this is aligned? 
    if (some_condition()) 
    { 
     T *const obj = new(buffer) T(); 
     // ... 
     obj->~T(); 
    } 
    else { /* use 'buffer' for something else */ } 
} 

Questo è anche possibile, o sei costretto ad utilizzare le estensioni del compilatore al fine di attuare questo?

+0

Interessante domanda. +1 per ricordare di colpire manualmente il distruttore (anche se sono piuttosto incerto su come farlo con un 'const'. Devo davvero rispolverare i miei posizionamenti' const'). – WhozCraig

+0

@WhozCraig: Grazie. Nota che il pointee non è const, il puntatore stesso è. :) – Mehrdad

+0

Sì, l'ho appena visto. = P – WhozCraig

risposta

7

Nella colonna Guru Of The Week #28, Herb Sutter utilizza un sindacato ma è meno robusto degli sforzi di Boost.

Boost's aligned_storage risolve i dettagli sanguinosi per te. Se osservi la sua implementazione, vedrai che utilizza MSCV __alignof o GCC __alignof__ e un altro modello: type_with_alignment.

Dalla mia base di codice, una volta ho usato (derivato dal link GotW sopra):

#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706) 
# pragma warning(push) 
# pragma warning(disable: 4371) 
#endif // #if (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706) 
     union AlignedStorage 
     { 
     char  storage[sizeof(T)]; 
     int16  dummy0; 
     int32  dummy1; 
     int64  dummy2; 
     float  dummy3; 
     double  dummy4; 
     long double dummy5; 
     void  (*dummy6)(); 
     struct  dummy7; 
     int   dummy7::*dummy8; 
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140050215) 
# pragma warning(push) 
# pragma warning(disable: 4121) 
#endif // #if (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140050215) 
     int   (dummy7::*dummy9)(int); 
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140050215) 
# pragma warning(pop) 
#endif // #if (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140050215) 

     }; // AlignedStorage 
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706) 
# pragma warning(pop) 
#endif // #if (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706) 

In questi giorni vorrei solo contare su Boost in quanto probabilmente copre molti più casi d'angolo e le specificità del compilatore

+0

Due problemi: (1) Sto chiedendo come questo è ** implementato ** in primo luogo. C'è un modo portatile per farlo o richiede le estensioni del compilatore? (2) Cosa devo dare come secondo parametro template (l'allineamento)? – Mehrdad

+0

Dopo la modifica n. 1, quindi stai dicendo che richiede le estensioni del compilatore? – Mehrdad

+0

Dopo la modifica n. 2, si, posso combinare tutti i tipi possibili per ottenere l'allineamento massimo, ma in molti casi allineo troppo i dati e spreca spazio. Sto cercando di ottenere lo ** stesso ** allineamento del tipo; non di più, non di meno. – Mehrdad

2

Il motivo per cui estensioni del compilatore come __alignof e __attribute__((aligned(n)) esiste che l'allineamento di determinazione e applicazione non può essere implementato in modo portabile in C e C++. Cioè lo standard non richiede mezzi per farlo.

+0

Non sono sicuro che tu stia cercando di dirlo * non è * implementato portabilmente, o se davvero * non può * essere implementato portabilmente. A quale ti riferisci? Lo standard – Mehrdad

+0

c/C++ lascia la libertà al compilatore, tutto deve comunque essere allineato al char almeno. In C++ 11 l'allineamento fa parte dello standard, l'allineamento è probabilmente portatile per la maggior parte delle architetture esistenti. – GameDeveloper

+0

@Mehrdad Lo standard C++ non richiede servizi per questo, quindi le estensioni. –