Wie kann ich nur die Füllbytes einer Klasse auf null setzen?

8

Ich möchte die Padding-Bytes einer Klasse auf 0 setzen, da ich Instanzen auf Byte-Ebene speichere / lade / vergleiche / hashe, und matter-initialized padding führt bei jeder dieser Operationen zu Nicht-Determinismus.

>

Ich weiß, dass dies erreichen wird, was ich will (für trivial kopierbare Typen):

%Vor%

Ich mag das aber nicht, aus zwei Gründen: Ich mag Konstruktorinitialisierungslisten, und ich weiß, dass das Setzen der Bits auf 0 nicht immer das Gleiche ist wie die Nullinitialisierung (zB Zeiger und Gleitkommazahlen müssen nicht unbedingt sein) habe null Werte, die alle 0 Bits sind).

Nebenbei gesagt, es ist offensichtlich auf Typen beschränkt, die trivial kopierbar sind, aber das ist für mich kein Problem, da die oben aufgeführten Operationen (Laden / Speichern / Vergleichen / Hashing auf Byte-Ebene) sowieso kopierbare Typen erfordern / p>

Was ich gerne hätte, wäre so etwas [magisches] Snippet:

%Vor%

Ich bezweifle, dass so etwas möglich ist, also wenn jemand eine nicht-hässliche Alternative vorschlagen kann ... Ich bin ganz Ohr:)

    
Ben Hymers 23.10.2013, 15:08
quelle

3 Antworten

7

Es gibt keine Möglichkeit, das in reinem C ++ vollautomatisch zu machen. Wir verwenden ein benutzerdefiniertes Codegenerierungssystem, um dies (unter anderem) zu erreichen. Sie könnten dies möglicherweise mit einem Makro erreichen, in das Sie alle Namen Ihrer Mitgliedsvariablen eingegeben haben. es würde einfach nach Löchern zwischen offsetof (memberA) + sizeof (memberA) und offsetof (memberB) suchen.

Alternativ serialisieren / hacken Sie elementweise anstatt als binäres Blob. Das sind zehn Arten von Reiniger.

Oh, eine andere Option - Sie könnten eine operator new angeben, die den Speicher explizit gelöscht hat, bevor Sie ihn zurückgeben. Ich bin kein Fan dieses Ansatzes, aber ..... es funktioniert nicht für die Stapelzuweisung.

    
Sneftel 23.10.2013, 15:13
quelle
2

Sie sollten gepolsterte Strukturen niemals beim binären Schreiben / Lesen verwenden. Ganz einfach, weil das Auffüllen von einer Plattform zur anderen variieren kann, was zu einer binären Inkompatibilität führt.

Verwenden Sie einige Compileroptionen wie #pragma pack (push, 1) , um das Auffüllen von zu deaktivieren, wenn Sie diese schreibbaren Strukturen definieren, und stellen Sie sie mit #pragma pack(pop) wieder her.

Das bedeutet leider, dass Sie die Optimierung verlieren. Wenn es sich um ein Problem handelt, können Sie sie durch vorsichtiges Entwerfen Ihrer Strukturen manuell auffüllen, indem Sie Dummy-Variablen einfügen. Dann wird die Null-Initialisierung offensichtlich, Sie geben diesen Dummies nur Nullen. Ich empfehle diesen "manuellen" Ansatz nicht, da er sehr fehleranfällig ist, aber da Sie binäre Blobs verwenden, sind Sie wahrscheinlich schon besorgt. Aber unbedingt vorher nicht gepufferte Strukturen benchmarken.

    
Agent_L 23.10.2013 15:25
quelle
2

Ich sah mich einem ähnlichen Problem gegenüber - und einfach zu sagen, dass dies eine schlechte Designentscheidung ist (gemäß dem Kommentar von dasblinkenlight), hilft nicht unbedingt, da Sie vielleicht keine Kontrolle über den Hashcode haben (in meinem Fall benutzte ich eine externe Bibliothek) ).

Eine Lösung besteht darin, einen benutzerdefinierten Iterator für Ihre Klasse zu schreiben, der die Byte der Daten durchläuft und die Auffüllung überspringt. Sie ändern dann Ihren Hashalgorithmus, um Ihren benutzerdefinierten Iterator anstelle eines Zeigers zu verwenden. Eine einfache Möglichkeit besteht darin, den Zeiger so zu templatisieren, dass er einen Iterator benötigt. Da die Semantik eines Zeigers und eines Iterators identisch sind, sollten Sie keinen Code über das Templatisieren hinaus ändern.

BEARBEITEN : Boost bietet eine nette Bibliothek, die es einfach macht, benutzerdefinierte Iteratoren zu Ihrem Container hinzuzufügen: Boost.Iterator .

Für welche Lösung Sie sich auch entscheiden, es ist höchst vorzuziehen, das Auffüllen des Paddings zu vermeiden, da dies bedeutet, dass Ihr Hashing-Algorithmus stark mit Ihrer Datenstruktur gekoppelt ist. Wenn Sie zwischen Datenstrukturen wechseln (oder wie Agent_L erwähnt, verwenden Sie die gleiche Datenstruktur auf einer anderen Plattform, die anders gepolt ist), dann werden verschiedene Hashes erzeugt. Auf der anderen Seite, wenn Sie nur die eigentlichen Daten selbst hashen, dann werden Sie immer dieselben Hash-Werte erzeugen, egal welche Datenstruktur Sie später verwenden.

    
JBentley 23.10.2013 15:29
quelle

Tags und Links