2014-02-13 15 views
6

Ich habe heute viel Mühe mit der Verfolgung eines wirklich ausweichenden Korruption Bugs.
Ich denke, es wäre nicht so schwer gewesen, es zu finden, wenn ich wirklich auf die Warnungen achtete, aber da ich keine relevanten Informationen darüber finden konnte, warum diese Warnung kam, ließ ich sie gleiten, was ein Fehler war .Alignment: Warnung C4316 in allen Klassen, die Alignment-Mitglieder haben

So, hier ist die inkriminierten Warnung Visual Studio 2013 gibt mir:

warning C4316: object allocated on the heap may not be aligned 16 

Und es erzeugt wird, wenn eine align (16) vorübergehend zu einem Konstruktor durch konstante Referenz vorbei, wie der folgende Code demonstrieren:

class Vector 
{}; 

__declspec(align(16)) class VectorA 
{}; 

class Shape 
{ 
public: 
    Shape(const Vector& vec) {} 
}; 

class ShapeA 
{ 
public: 
    ShapeA(const VectorA& vec) : mVec(vec) {} 

private: 
    VectorA mVec; 
}; 

int main(int argc, char *argv[]) 
{ 
    Shape* shape = new Shape(Vector()); // ok 
    ShapeA* shapea = new ShapeA(VectorA()); // warning C4316: 
          // object allocated on the heap may not be aligned 16 
} 

die ein paar Fragen bringt:

  1. A s Ich bin nicht verantwortlich für die Ausrichtung der Struktur (es kommt aus einer Bibliothek), ich kann das nicht wirklich beeinflussen. Was wäre der empfohlene Weg, um dieses Problem zu umgehen?

  2. Da dies eine Warnung ist, vermutete ich, dass es keinen dramatischen Effekt haben würde. Aber die Effekte, die ich entdeckte, waren ziemlich dramatisch und still (was nur dann der Fall war, wenn man einen völlig unabhängigen Verweis auf einen Float auf eine SQLite-Funktion übertrug). (Edit: das ist eigentlich falsch, der Heap wurde nicht deswegen korrumpiert) Ist es wirklich so einfach wie: "Dieser Code wird sicherlich Heap-Korruption verursachen, tun Sie es nicht." ? Oder gibt es eine komplexere Kette von Aktionen, die so etwas bewirken?

Eine Abhilfe ich gedacht ist, eine unique_ptr zu dem ausgerichteten Objekt zu haben, anstatt sie als direkte Mitglied zu haben, aber ich bin ein bisschen zurückhaltend überall hinzufügen unique_ptr ich vor Ebene structs hatte (auch wenn es erlaubt es mir, meinen Code) Pimpl

Nachtrag

Wie sich herausstellte war ich Subklassen der Klasse Vectora die neue tat bieten eine löschen Überlastungen die richtige Ausrichtung zu gewährleisten, aber meine eigene Unterklasse nicht. Aber ein zweites Vorkommen dieser Warnung im nächsten Absatz ist komplizierter loswerden:

Erweitert

Die andere Situation die Warnung Herstellung ist folgende:

__declspec(align(16)) class VectorA 
{ 
    void* operator new(size_t size) 
    { 
     void* p = _aligned_malloc(size, 16); 
     if(p == 0) throw std::bad_alloc(); 
     return p; 
    } 

    void operator delete(void *p) 
    { 
     VectorA* pc = static_cast<VectorA*>(p); 
     _aligned_free(p); 
    } 
}; 

class ShapeB 
{ 
public: 
    ShapeB() {} 

private: 
    VectorA mVec; 
}; 

int main() 
{ 
    std::unique_ptr<BoxShapeB> shapeb = std::make_unique<BoxShapeB>(); 
} 

Es scheint, jede Klasse von meins mit einem ausgerichteten Element wie in diesem Beispiel wird auch eine Warnung erzeugen, wenn es instanziiert wird. Wie ich oben sagte, ist ein Weg, um die Warnung zu entfernen, Zeiger auf dieses Mitglied zu haben. Diese Warnung trat in den Vorgängerversionen von Visual Studio nicht mit dem gleichen genauen Code auf. Daher lautet meine Frage: Inwieweit ist das Obenstehende falsch und sollte es um jeden Preis vermieden werden? Was sollte ich von der Warnung halten?

Angenommen, die meisten meiner Klassen haben alle eine gemeinsame Basisklasse Object, und die meisten meiner Klassen haben align (16) Vector als Mitglieder, lohnt es sich, nur die überladenen neuen und löschen in dieser Basisklasse und vergessen alle meine Mitglieder Vektoren zu Zeigern machen? Würde dieser Ansatz funktionieren?

Antwort

2

Dieses Problem ist nicht mit dem Übergeben von ausgerichteten Struktur durch const Referenz oder nicht, wie Sie vorschlagen. See this documentation of C4316.Problem ist, dass Sie eine ausgerichtete Struktur deklarieren, aber keine geeigneten new/delete-Operatoren bereitstellen, die diese Ausrichtung verarbeiten.

Wenn Sie solche Situation mit 3rd-Party-Bibliothek, die vor-gebaut ist, dann IMHO sollten Sie eine Anfrage an seine Autoren melden, um dieses Problem zu beheben. Wenn Sie diese Bibliothek selbst erstellen können, können Sie die genannten Operatoren selbst hinzufügen.

+0

Yeah, Sie haben Recht, es geschah nicht, weil die Bibliothek nicht neue/löschte, aber weil ich es subclassed und sie nicht in meiner eigenen Unterklasse zur Verfügung stellte. Aber das zweite Problem steht immer noch, also werde ich neu formulieren. – MONK

+0

Wenn die ausgerichtete Klasse als Mitglied in einer anderen Klasse vorliegt, wird die Warnung ausgegeben (im Gegensatz zu der ersten, selbst wenn die neuen Löschüberladungen definiert sind) – MONK

+0

@MONK Ich denke, das zweite Problem ist ähnlich dem ersten. In der ersten hat man die ausgerichtete Struktur geerbt und brauchbare Operatoren benötigt. Ich denke, der zweite Fall ist der gleiche. Aber das ist nur eine Vermutung. – Bogdan

1

So nach ein wenig mit Dr.-Speicher und einer Sitzung des Gesamt Bug Lösung von Hantieren, stellt sich heraus:

  1. Der Haufen wegen Ausrichtungsprobleme nicht beschädigt wurde. Das heißt, ich weiß immer noch nicht, in welchem ​​Ausmaß diese Warnung alarmierend sein sollte, aber ich entschied mich trotzdem für eine Lösung:

  2. Um diese Warnung zu vermeiden, habe ich die folgende Lösung verwendet, die mir Befriedigung gibt für den Moment: Machen Sie eine Klasse Align16, die alle neuen und löschenden Operatoren überlädt, um _aligned_malloc und _aligned_free zu verwenden. Dann muss jede Klasse, die ein ausgerichtetes Element enthält, von Align16 erben, damit die Warnung nicht mehr angezeigt wird.
    Ich verstehe, dass es nicht tragbar ist wegen _aligned_malloc, also wenn ich möchte, dass mein Code tragbar ist Bullet Physics hat eine benutzerdefinierte Implementierung, die in seinen Speicherzuordnern funktioniert, auf die ich zurückgreifen kann, wenn nötig.

+0

Haben Sie versucht, den Struct Member Alignment-Parameter in den C++ - Code-Generierung-Parametern Ihres Projekts zu ändern? Sie können es für Ihr gesamtes Projekt auf 16 Byte setzen. –

Verwandte Themen