2013-10-07 8 views
5

Sto usando std::aligned_storage come memoria di supporto per un modello di variante. Il problema è che, una volta abilitato -O2 su gcc, comincio a ricevere gli avvisi di "puntatore con puntatore di dereferenziazione che interromperà il rigoroso aliasing".Come evitare gli errori di aliasing severo quando si utilizza aligned_storage

Il vero modello è molto più complessa (tipo controllato in fase di esecuzione), ma un esempio minimo per generare l'avviso è:

struct foo 
{ 
    std::aligned_storage<1024> data; 

    // ... set() uses placement new, stores type information etc ... 

    template <class T> 
    T& get() 
    { 
    return reinterpret_cast<T&>(data); // warning: breaks strict aliasing rules 
    } 
}; 

Sono abbastanza sicuro boost::variant sta facendo essenzialmente la stessa cosa come questa, ma non riesco a trovare il modo in cui evitano questo problema.

Le mie domande sono:

  • Se si utilizza aligned_storage in questo modo viola rigoroso-aliasing, come dovrei essere usando?
  • Esiste effettivamente un problema di aliasing stretto in get() dato che non ci sono altre operazioni basate su puntatore nella funzione?
    • E se lo get() è in linea?
    • Che dire di get() = 4; get() = 3.2? È possibile riordinare quella sequenza a causa di int e float di tipi diversi?
+0

non l'allineamento influisce il problema aliasing in alcun modo ?! aspettarsi che sia parte del motivo (ma questo non cambia affatto al punto che lo standard lo fobide, non è così?) – dhein

+0

@Zaibis No, usando 'aligned_storage' rispetto a qualsiasi altro tipo come un buffer shouldn ' t fare qualsiasi differenza Il motivo per cui ho specificato 'aligned_storage' qui è che sembra essere stato progettato pensando a questo tipo di utilizzo. – marack

+0

@marack: non dovresti (e non ti è permesso) usare direttamente 'aligned_storage'. Ho modificato la mia risposta per cercare di renderlo (anche) più chiaro. – rici

risposta

5

std::aligned_storage fa parte del <type_traits>; come la maggior parte degli altri abitanti di quel file di intestazione, è solo un supporto per alcuni typedef e non è pensato per essere usato come un tipo di dati. Il suo compito è di prendere una misura e un allineamento, e renderti un tipo POD con queste caratteristiche.

Non è possibile utilizzare direttamente std::aligned_storage<Len, Align>. È necessario utilizzare std::aligned_storage<Len, Align>::type, il tipo trasformata, che è "un tipo POD adatto per l'uso come immagazzinaggio inizializzata per qualsiasi oggetto le cui dimensioni sono al massimo Len ed il cui allineamento è un divisore di Align." (Align default è il più grande allineamento utile maggiore o uguale a Len.)

Come note standard del C++, normalmente il tipo restituito dal std::aligned_storage sarà un array (delle dimensioni specificate) di unsigned char con un identificatore di allineamento. Che evita la regola "non rigoroso aliasing", perché un tipo di personaggio può alias qualsiasi altro tipo.

Così si potrebbe fare qualcosa di simile:

template<typename T> 
using raw_memory = typename std::aligned_storage<sizeof(T), 
               std::alignment_of<T>::value>::type; 

template<typename T> 
void* allocate() { return static_cast<void*>(new raw_memory<T>); } 

template<typename T, typename ...Arg> 
T* maker(Arg&&...arg) { 
    return new(allocate<T>()) T(std::forward<Arg>(arg)...); 
} 
+0

Ahh grazie. Non mi rendevo conto che 'aligned_storage' era un tratto di esporre un tipo piuttosto che il tipo in sé. Come lei ha ricordato, usando 'aligned_storage <...> :: type' risolve correttamente il rigoroso problema aliasing. – marack

+4

Questo caso è * altro tipo * aliasing di un tipo di carattere. La rigida regola di aliasing non è simmetrica, ma mette fuori legge * un altro tipo di carattere di aliasing * ma consente l'alias del tipo di carattere * altro tipo * (che non sta succedendo qui). Tuttavia, [questa risposta] (http://stackoverflow.com/questions/13466556/aligned-storage-and-strict-aliasing) sostiene che 'aligned_storage' non viola il rigoroso aliasing per altri motivi (anche se non lo seguo del tutto la sua argomentazione). –

Problemi correlati