2013-01-16 18 views
5

Mögliche Duplizieren:
Classes store data members in sequential memory?Klassenvariablen - Ausrichtung

nur fragen wollte, warum die folgende richtig ist:

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

oder mit anderen Worten: Warum ist es immer garantiert, dass x, y und z sind immer Größe von (T) Einheiten auseinander im Speicher. Kann es zwischen zwei dieser Variablen keine Fragmentierungslöcher geben, sodass der Operator einen falschen Wert zurückgeben kann?

+0

Wenn Sie die Indizierung benötigen, warum es nicht machen 'Vorlage Klasse Vector3 {public: std :: array xs; }; '? – Fanael

Antwort

6

Es ist nicht garantiert, dass x, y und z immer sizeof(T) Einheiten auseinander im Speicher befinden. Es können Füllbytes dazwischen eingefügt werden.
Es ist als Implementierungsdetail ausgelassen.
Es ist nur garantiert, dass es zwischen dem Anfang der Klasse/Struktur und ihrem ersten Member für POD-Strukturen/Klassen keine Auffüllung geben wird.

Es ist nicht garantiert, dass die Implementierung von operator[] in Ihrem Code immer funktioniert.

Referenz:
C++ 11: 9.2 Klassenmitglieder [class.mem]

14) nicht-statische Datenelemente einer (nicht-union) Klasse mit der gleichen Zugriffskontrolle (Ziffer 11) werden so zugewiesen, dass spätere Mitglieder höhere Adressen innerhalb eines Klassenobjekts haben. Die Reihenfolge der Zuordnung von nicht statischen Daten Mitglieder mit unterschiedlicher Zugriffskontrolle ist nicht spezifiziert (11). Implementation Alignment-Anforderungen möglicherweise bewirken, dass zwei benachbarte Mitglieder nicht sofort hintereinander zugeordnet werden; Anforderungen für Platz für die Verwaltung virtueller Funktionen (10.3) und virtueller Basisklassen (10.1).

+0

Was meinen Sie mit "Es ist als Implementierungsdetail ausgelassen."? –

+0

Auch die Garantie bezüglich der Adresse des ersten Mitglieds gilt nur für POD-Strukturen.(Oder vielleicht für Layout-kompatible Strukturen in C++ 11.) –

+0

@AdamMagaluk: Es bedeutet, dass der Compiler frei ist, so viele Bytes von Zwischenräumen, die zwischen Klassen/Struktur-Mitgliedern benötigt werden, hinzuzufügen. Der Standard schreibt diesbezüglich keine spezifische Anforderung vor. –

0

Um Fragmentierung Löcher zu vermeiden Sie die Ausrichtung auf diese Weise steuern:

#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 

Wenn Sie eine C++11 compiler die Ausrichtung in einer standard way steuern können Sie verwenden können.

Aber wenn Sie nicht über die Speicher Darstellung der Klasse kümmern, denken Sie an eine union zu verwenden:

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

Mit der Vereinigung, müssen Sie über die Ausrichtung, um nicht kümmern zu acces jede Komponente mit []:

Vec3<unsigned int> v3; 

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

Ist irgendwo angegeben, dass in Ihrer Union-Lösung die Felder ausgerichtet werden (z. B. x und Wert [0], y und Wert [1])? Es macht * Sinn *, aber ist das eigentlich irgendwo angegeben/garantiert? – rmhartog

+0

Ja, 'x' und' value [0] ',' y' und 'value [1]' ... haben die gleiche Adresse ... aber das kann ich nicht garantieren zwischen 'x' <->' y', ' Wert [0] '<->' Wert [1] 'Sie werden padding Bytes finden; Dies hängt vom Datentyp, der Datenausrichtung und der Ausrichtungssteuerung der "Union" ab –