X
Weil mich die boost-Lösung für korrektes Alignment fasziniert, poste ich mal, was ich gelernt habe ... also bitte mich zurechtweisen, wenns falsch ist
template<class T>
struct alignment_hack
{
char c;
T t;
};
Diese Hilfsklasse beinhaltet die notwendige Alignment-Lücke zwischen dem char und dem Typ T. Erfordert T ein 32-bit Alignment, so ordnet es der Compiler an Offset 4 ein. Mit dem Ausdruck
sizeof(alignment_hack<T> - sizeof(T)) lässt sich also die Alignment-Grüße bestimmen.
Wenn also für alle Größen ein template spezialisiert ist...
(Folgendes ist nur ein primitivstes Beispiel, boost ist wesentlich vollständiger und compiler-unabhängiger)
template<unsigned size> struct aligned_type { };
template<> struct aligned_type<1> { typedef char type; };
template<> struct aligned_type<2> { typedef short type; };
template<> struct aligned_type<4> { typedef long type; };
template<> struct aligned_type<8> { typedef long long type; };
..kann man für jedes mögliche T eine korrekt ausgerichteten Hilfsvariable anlegen.
template<class T> struct aligned_storage
{
union
{
char mem[sizeof(T)];
typename aligned_type<sizeof(alignment_hack<T>) - sizeof(T)>::type aligned_var;
};
};
Packt man diese Hilfsvariable mit einem char-Array in einen union ist der union auch für ein T richtig
aligned ...
Und dann sollte man ohne Probleme ein
new (reinterpret_cast<void*>(store.mem)) T();
bzw. ein reinterpret_cast<T*>(store.mem)->~T();
ausführen können.
Es ist schon übel. Ich hab früher in C oftmals ein char array irgend wo angelegt und dann dort
wild strukturen rein und raus-gecastet zwecks einfacher Speicherung oder übertragung auf nem Socket. Und dann erfährt man so ganz nebenbei, dass das nur auf nem 32bit PC problemlos geht aber auf den meisten anderen CPUs Exceptions auslöst oder zumindest die Performance runterzieht ... ja man lernt eben nie aus.
Fazit: boost rulez!
Lg XOR
@pumuckl:
Ich frage mich, ob dem Urheber dieses Codes nicht bewusst war, dass man Daten auch auf dem Stack lokal anlegen kann: ... diese Member sind sowas von sinnlos.
this->m_doc1 = new char[128];
this->m_doc2 = new char[128];
read_doc(this->m_doc1, 128, &this->m_doc1_len);
process_data(this->m_doc1, this->m_doc1_len);
delete[] this->m_doc1;
delete[] this->m_doc2;
this->m_doc1 = new char[128];
this->m_doc2 = new char[128];
read_doc(this->m_doc2, 128, &this->m_doc2_len);
process_data(this->m_doc2, this->m_doc2_len);
delete[] this->m_doc1;
delete[] this->m_doc2;
Sobald ich also diesen Kot weggemacht habe, komme ich gerne auf deinen Vorschlag mit der new Überladung zurück. ... Im Idealfall sind dann die meisten news gar nicht mehr vorhanden.
@krümelkacker:
Das Color Beispiel war von mir gewählt, weil hier 3 chars zusammengefasst werden, die Struktur aber ein größeres Alignment haben kann (etwa 4). sizeof(Color) kann dann je nach Einstellung variieren (3, 4, ...). Ich fragte mich, ob bei einem char m_mem[sizeof(Color) + 1] durch ein *reinterpret_cast<Color*>(m_mem) = Color(0,0,0); das 4. Byte auch mitüberschrieben werden kann, wenn sizeof(Color) 3 wäre ... aber dieses hinten angehängte Flag ist eh Schwachsinn und würde in einen eigenen Member kommen. (Ursprünglich wollte ich das Flag ja in das erste char setzen und placment-new mit nem Pointer auf das 2. char aufrufen ... aber das wäre ja noch viel viel böser gewesen