2013-10-07 14 views
5

Używam std::aligned_storage jako pamięci wewnętrznej dla wariantu szablonu. Problem polega na tym, że po włączeniu -O2 w gcc zacznę otrzymywać ostrzeżenia o "przeszkadzającym wskaźniku typu" dereferencing ", które przerwie ścisłe aliasowanie.Jak uniknąć ścisłych błędów aliasingu podczas korzystania z polecenia adjust_storage

Prawdziwy szablon jest znacznie bardziej skomplikowane (typ sprawdzana przy starcie), ale minimalny przykład wygenerować ostrzeżenie jest:

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 
    } 
}; 

jestem całkiem pewny boost::variant robi w zasadzie to samo, co ten, ale nie mogę znaleźć sposobu na uniknięcie tego problemu.

Moje pytania są następujące:

  • W przypadku korzystania aligned_storage w ten sposób jest niezgodny strict-aliasing, jak należy go używać?
  • Czy istnieje rzeczywiście problem z aliasingiem ścisłym w get(), biorąc pod uwagę, że w tej funkcji nie ma innych operacji opartych na wskaźnikach?
    • Co się stanie, jeśli zostanie wstawiona linia get()?
    • Co z numerem get() = 4; get() = 3.2? Czy ta kolejność może być ponownie uporządkowana z powodu różnych typów? int i float?
+0

powoduje wyrównanie wpływa problem aliasingu w jakikolwiek sposób ?! spodziewaj się, że jest to część tego powodu (ale to nie zmienia w ogóle punktu, w którym standard je fobiduje, czy nie?) – dhein

+0

@Zaibis Nie, używając 'aligned_storage' w przeciwieństwie do jakiegokolwiek innego typu jako bufora shouldn ' t zrobić jakąkolwiek różnicę. Powodem, dla którego określiłem tutaj "matching_storage", jest to, że wydaje się, że został zaprojektowany z myślą o takim użyciu. – marack

+0

@marack: nie powinieneś (i tak naprawdę nie wolno ci) korzystać bezpośrednio z "aligned_storage". Zmieniłem moją odpowiedź, aby spróbować uczynić to (jeszcze bardziej) bardziej przejrzystym. – rici

Odpowiedz

5

std::aligned_storage jest częścią <type_traits>; podobnie jak większość pozostałych mieszkańców tego pliku nagłówkowego, jest tylko uchwytem dla niektórych typów i nie jest przeznaczony do użycia jako typ danych. Jego zadaniem jest zmierzenie rozmiaru i wyrównania i uczynienie z ciebie typu POD o tych cechach.

Nie można bezpośrednio użyć std::aligned_storage<Len, Align>. Musisz użyć std::aligned_storage<Len, Align>::type, przekształconego typu, który jest "typem POD odpowiednim do użycia jako niezainicjowany magazyn dla dowolnego obiektu, którego rozmiar wynosi co najwyżej Len, a którego wyrównanie jest dzielnikiem Align." (Align domyślnie największej użytecznej wyrównania większej niż lub równej Len.)

jak C++ standardowych banknoty, zwykle zwrócony przez std::aligned_storage będzie tablica (o określonej wielkości) z unsigned char ze specyfikacją wyrównania. W ten sposób unika się zasady "brak ścisłego aliasingu", ponieważ typ znaku może być aliasem dowolnego innego typu.

Więc można zrobić coś takiego:

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 dzięki. Nie zdawałem sobie sprawy, że "aligned_storage" jest cechą eksponującą typ, a nie sam typ. Jak już wspomniałeś, używanie 'aligned_storage <...> :: type' rozwiązuje poprawnie problem aliasingu strict. – marack

+4

Ten przypadek to * inny typ * aliasujący typ znaku. Zasada ścisłego aliasingu nie jest symetryczna, zakazuje * innego typu znaku aliasingowego * ale dopuszcza aliasing typu znakowego * inny typ * (co nie dzieje się tutaj). Jednak [ta odpowiedź] (http://stackoverflow.com/questions/13466556/aligned-storage-and-strict-aliasing) argumentuje, że 'aligned_storage' nie narusza ścisłego aliasingu z innych powodów (chociaż nie całkiem śledzę jego argument). –

Powiązane problemy