2011-08-05 11 views
6

Mam tablicę, która jest używana jako podstawowej pamięci obiektu typu T:Jak mogę symulować alignas (T)?

char memory[sizeof T]; 
. 
. 
. 
new(memory) T(whatever); 

Jak mogę się upewnić memory jest wyrównane do T obiektów? W C++ 0x mógłbym powiedzieć:

alignas(T) char memory[sizeof T]; 

, ale Visual Studio 2010 nie obsługuje jeszcze tej konkretnej funkcji.

Odpowiedz

10

Typowym (przenośnym) rozwiązaniem jest umieszczenie deklaracji pamięci w zjednoczeniu z dowolnym wbudowanym typem w T wymagającym najbardziej wyrównania. Najprościej byłoby użyć unii z wszystkich możliwych kandydatów:

union MaxAlign 
{ 
    int     i  ; 
    long    l  ; 
    long long   ll ; 
    long double   ld ; 
    double    d  ; 
    void*    p  ; 
    void (*    pf)() ; 
    MaxAlign*   ps ; 
} ; 

union 
{ 
    MaxAlign dummyForAlignment; 
    unsigned char memory[sizeof(T)]; 
} rawT; 

mam jeszcze usłyszeć o wiele mniej spotkanie, ekspres do którego powyższa nie wystarczyć. Zwykle wystarcza tylko double. (Jest to na pewno wystarczające dla firmy Intel i urządzenia Sparc).

W niektórych ekstremalnych przypadkach może to spowodować przydzielenie większej ilości pamięci niż jest to konieczne, np. , np. jeśli T zawiera tylko jeden lub dwa char. Większość czasu , to naprawdę nie ma znaczenia, i nie warto martwić, ale jeśli jest dodaje można stosować:

namespace MyPrivate { 

template< typename T, bool isSmaller > 
struct AlignTypeDetail ; 

template< typename T > 
struct AlignTypeDetail< T, false > 
{ 
    typedef T type ; 
} ; 

template< typename T > 
struct AlignTypeDetail< T, true > 
{ 
    typedef char type ; 
} ; 

template< typename T, typename U > 
struct AlignType 
{ 
    typedef typename AlignTypeDetail< U, (sizeof(T) < sizeof(U)) >::type 
         type ; 
} ; 
} 

template< typename T > 
union MaxAlignFor 
{ 
    typename MyPrivate::AlignType< T, char >::type  c ; 
    typename MyPrivate::AlignType< T, short >::type  s ; 
    typename MyPrivate::AlignType< T, int >::type   i ; 
    typename MyPrivate::AlignType< T, long >::type  l ; 
    typename MyPrivate::AlignType< T, long long >::type ll ; 
    typename MyPrivate::AlignType< T, float >::type  f ; 
    typename MyPrivate::AlignType< T, double >::type  d ; 
    typename MyPrivate::AlignType< T, long double >::type ld ; 
    typename MyPrivate::AlignType< T, void* >::type  pc ; 
    typename MyPrivate::AlignType< T, MaxAlign* >::type ps ; 
    typename MyPrivate::AlignType< T, void (*)() >::type pf ; 
} ; 

W tym przypadku MaxAlignFor<T> nigdy nie będzie większy niż T (i mieć wystarczające wyrównanie, ponieważ wymagane wyrównanie będzie nigdy większe niż nigdy nie będzie większe niż rozmiar T).

Należy zauważyć, że żadna z powyższych formalnie nie jest gwarantowana przez standard. Ale będzie działać w praktyce.

+0

Masz na myśli 'union' zamiast' enum', prawda? – fredoverflow

+0

Tak. Przykłady jasno to potwierdzają, mam nadzieję. –

+0

@Mehrdad Mówi, że VC++ nie obsługuje pewnej funkcji. Nie mówi, że był to jedyny używany kompilator. –

5

Googling dla vc++ align pokazuje this page: użyj __declspec(align(#)).

+4

Co, jak wyraźnie wskazuje początkowe "__", jest rozszerzeniem specyficznym dla kompilatora. –

+1

@JamesKanze: to 3 lata za późno, ale mimo to o tym wspomnę ... w pytaniu brzmi Visual C++ :) – Mehrdad

+0

@JamesKanze: Przepraszam, właściwie skomentowałem telefonem i nie zdawałem sobie sprawy, że " m komentując niewłaściwy wpis. Moja odpowiedź pod twoim postem miała być tutaj, w odpowiedzi na twój komentarz tutaj. – Mehrdad

2

Albo przydzielić pamięć na stercie (która ma gwarancję wyrównania) lub użyć boost::aligned_storage.

3

Jeżeli T jest standardowym układ i związek jest odpowiednio ukształtowany, a następnie

union 
{ 
    T t; 
    char memory[sizeof T]; 
}; 

powinny być wyrównane.

Powiązane problemy