2013-01-16 15 views
5

Powiel możliwe:
Classes store data members in sequential memory?klasy zmienne - dostosowanie

Chciałem tylko zapytać, dlaczego następujących jest poprawna:

template<class T> 
class Vec3 { 
public: 
    // values 
    T x,y,z; 

    // returns i-th komponent (i=0,1,2) (RHS array operator) 
    const T operator[] (unsigned int i) const { 
    return *(&x+i); 
    } 
} 

lub innymi słowy: Dlaczego jest to zawsze gwarantowane, że x, y i z zawsze są wielkościami (T) w pamięci. Czy nie mogą być kiedykolwiek otwory fragmentacji pomiędzy dwoma z tych varibles, pozwalając tym operatorowi zwracać fałszywą wartość?

+0

Jeśli potrzebujesz indeksowanie, dlaczego nie zrobić to 'szablon klasa Vector3 {public: std :: array xs; }; '? – Fanael

Odpowiedz

6

Jest nie zagwarantować, że x, y i z są zawsze sizeof(T) jednostki od siebie w pamięci. Między dodanymi bajtami mogą znajdować się dopełnienia.
Został pominięty jako szczegół implementacji.
Gwarantowane jest tylko to, że nie będzie dopełnienia pomiędzy początkiem klasy/struktury a jej pierwszym elementem dla struktur/klas POD. Nie można zagwarantować, że implementacja operator[] w kodzie będzie działać zawsze.

odniesienia:
C++ 11: 9,2 członków klasy [class.mem]

14) Nonstatic zgromadzonych danych z pomocą (nie-Union) o tej samej klasy kontroli dostępu (punkt 11) są przydzielane tak, aby późniejsi członkowie mieli wyższe adresy w obrębie obiektu klasy. Kolejność przydzielania niestatycznych danych członkom o różnej kontroli dostępu jest nieokreślona (11). Wymogi dotyczące dopasowania do wdrożenia mogą być następujące: powodują, że dwóch sąsiednich członków nie będzie przydzielanych bezpośrednio po sobie;, więc może wymagać przestrzeni do zarządzania funkcjami wirtualnymi (10.3) i wirtualnymi klasami podstawowymi (10.1).

+0

Co masz na myśli przez "Zostało pominięte jako szczegół implementacji."? –

+0

Nawet gwarancja dotycząca adresu pierwszego elementu jest ważna tylko dla struktur POD.(A może w przypadku struktur zgodnych z układem w C++ 11). –

+0

@AdamMagaluk: Oznacza to, że kompilator może dodać tyle bajtów wypełnienia, jakie są wymagane między elementami klasy/struktury. Norma nie wymaga żadnych szczególnych wymagań w tym zakresie. –

0

W celu uniknięcia fragmentacji otwory można kontrolować wyrównanie w ten sposób:

#ifdef compiling_with_msvc 
#pragma pack(1) 
#endif 
template<class T> 
class Vec3 { 
public: 
    // values 
    T x,y,z; 

    // returns i-th komponent (i=0,1,2) (RHS array operator) 
    const T operator[] (unsigned int i) const { 
     return *(&x+i); 
    } 
#ifdef compiling_with_gcc 
}__attribute__((packed)); 
#else 
}; 
#endif 

Jeśli można użyć C++11 compiler można kontrolować wyrównanie w standard way.

Ale jeśli nie dbają o reprezentację pamięci klasy, pomyśl o użycie union:

template <typename T> 
union Vec3 
{ 
    T x, y, z; 
    struct 
    { 
     T value[3]; 
    } vector; 
}; 

z Unią, nie trzeba się martwić o dopasowaniu w celu acces każdy składnik z []:

Vec3<unsigned int> v3; 

v3.vector.value[0] = 1; 
v3.vector.value[1] = 2; 
v3.vector.value[2] = 3; 
+0

Czy jest rzeczywiście określone gdzieś, że w twoim rozwiązaniu związków, pola będą wyrównane (np. X i wartość [0], y i wartość [1])? Czyni * poczucie *, ale czy jest to rzeczywiście określone/gwarantowane w dowolnym miejscu? – rmhartog

+0

Tak, 'x' i' wartość [0] ',' y' i 'wartość [1]' ... będą miały ten sam adres ... ale nie mogę zagwarantować, że między 'x' <->' y', ' value [0] '<->' value [1] 'znajdziesz dopełnienie bajtów; będzie zależeć od typu danych, wyrównania danych i sterowania wyrównaniem "unii" –