verhindert nicht ausgerichtete Daten auf dem Heap

8

Ich baue eine Klassenhierarchie, die SSE-Eigenschaftsfunktionen verwendet, und daher müssen einige der Mitglieder der Klasse 16-Byte-ausgerichtet sein. Für Stack-Instanzen kann ich __declspec(align(#)) verwenden, so:

%Vor%

Nun, da __declspec(align(#)) eine Kompilierungsanweisung ist, kann der folgende Code zu einer nicht ausgerichteten Instanz von Vector auf dem Heap führen:

%Vor%

Auch das kann ich leicht lösen, indem ich die neuen und delete Operatoren überlasten kann, um _aligned_malloc und _aligned_free entsprechend zu verwenden. Wie so:

%Vor%

So weit so gut .. aber hier ist mein Problem. Betrachten Sie den folgenden Code:

%Vor%

Da die myclass Instanz MyClass erstellt wird statisch auf einer dynamische Instanz NotMyClass WIRD myclass 16-Byte relativ wegen __declspec(align(16)) -Richtlinie des Vector zum Anfang des NMC ausgerichtet sein. Aber das ist wertlos, da NMC dynamisch auf dem Heap mit NotMyClass der zugeordnet ist neuer Operator, die nesessarily nicht gewährleisten (und auf jeden Fall wahrscheinlich nicht) 16-Byte-Ausrichtung.

Bisher kann ich nur zwei Ansätze für den Umgang mit diesem Problem vorstellen:

  1. Verhindern, dass MyClass-Benutzer den folgenden Code kompilieren können:

    %Vor%

    Bedeutung, Instanzen von MyClass kann nur dynamisch erstellt werden, um die neuen Betreiber, damit sichergestellt wird, dass alle Instanzen von MyClass sind wirklich dynamisch mit MyClass der allocatted überlastet neu. Ich habe einen weiteren Thread dazu konsultiert, wie das zu erreichen ist und habe ein paar tolle Antworten bekommen: C ++, verhindert Klasseninstanz erzeugt wird auf dem Stapel (während der Kompilierung)

  2. Revert von Vector Mitglieder in meiner Klasse hat und nur Zeiger als Mitglieder Vektor hat, die ich vergeben und freigeben mit _aligned_malloc und _aligned_free im Ctor und dtor ist. Diese methos scheint roh und fehleranfällig, da ich nicht der einzige Programmierer diese Klassen zu schreiben bin (MyClass leitet sich von einer Basisklasse und viele dieser Klassen verwenden SSE).

Da jedoch beide Lösungen in meinem Team verpönt sind, komme ich zu Ihnen, um Vorschläge für eine andere Lösung zu machen.

    
eladidan 22.06.2010, 18:12
quelle

3 Antworten

4

Wenn Sie der Heap-Zuweisung den Vorzug geben, ist eine andere Idee, den Stack zu überzuordnen und manuell auszurichten (die manuelle Ausrichtung wird in diese SO Post ). Die Idee ist, Byte-Daten ( unsigned char ) mit einer Größe zuzuteilen, die garantiert eine ausgerichtete Region der notwendigen Größe enthält ( +15 ), dann die ausgerichtete Position durch Abrunden von der am meisten verschobenen Region ( x+15 - (x+15) % 16 , oder x+15 & ~0x0F ). Ich habe ein funktionierendes Beispiel dieses Ansatzes mit Vektoroperationen auf Codepad (für g++ -O2 -msse2 ) veröffentlicht. Hier sind die wichtigen Bits:

%Vor%

Der Konstruktor stellt sicher, dass vPtr ausgerichtet ist (beachten Sie die Reihenfolge der Elemente in der Klassendeklaration ist wichtig).

Dieser Ansatz funktioniert (die Heap- / Stack-Zuweisung von enthaltenden Klassen ist für die Ausrichtung irrelevant), ist portabl-ish (ich denke, die meisten Compiler bieten einen Zeiger der Größe uint uintptr_t ) und verlieren keinen Speicher. Aber es ist nicht besonders sicher (sicher sein, dass der ausgerichtete Zeiger unter Kopie gültig ist, usw.), verschwendet (fast) so viel Speicher wie es verwendet wird, und manche finden die reinterpret_casts geschmacklos.

Die Risiken von ausgerichteten Operationen / nicht ausgerichteten Datenproblemen könnten größtenteils eliminiert werden, indem diese Logik in ein Vector-Objekt eingekapselt wird, wodurch der Zugriff auf den ausgerichteten Zeiger kontrolliert und sichergestellt wird, dass er bei der Konstruktion ausgerichtet wird und gültig bleibt.

    
academicRobot 23.06.2010, 02:11
quelle
1

Sie können "placement new" verwenden.

%Vor%

Natürlich müssen Sie vorsichtig sein, wenn Sie das Objekt zerstören, indem Sie den Destruktor aufrufen und dann den Raum freigeben. Sie können nicht einfach löschen aufrufen. Sie könnten shared_ptr & lt; & gt; mit einer anderen Funktion, um automatisch damit umzugehen; Es hängt davon ab, ob der Aufwand für den Umgang mit einem shared_ptr (oder einem anderen Wrapper des Zeigers) ein Problem für Sie darstellt.

    
janm 23.06.2010 02:57
quelle
0

Der kommende C ++ 0x-Standard schlägt Funktionen für den Umgang mit Rohspeicher vor. Sie sind bereits in VC ++ 2010 (innerhalb des Namensraums tr1 ) enthalten.

%Vor%

Das sind Typen, Sie können sie wie folgt verwenden:

%Vor%

Dann kannst du deine Klasse deklarieren:

%Vor%

Schließlich brauchst du eine Umwandlung, um es zu manipulieren (es ist bis jetzt roher Speicher):

%Vor%     
Matthieu M. 23.06.2010 06:24
quelle

Tags und Links