Eigene Klassen, die Pointer enthalten in Binary-Datei speichern?
-
314159265358979 schrieb:
Ich habe doch nur ein & vergessen, kann doch mal passieren Schnucki.
Trotzdem 2 Casts zuviel.
-
Erklär mal bitte.
-
reinterpret_cast ist ein Konstrukt, dass sparsam eingesetzt werden sollte. Außerdem sollte man sich nicht unnötig wiederholen. Mithin ist eine eigene Funktion dafür angebracht. Erfahrungsgemäß werden gerade solche Codestücke wie oben gerne 1:1 in produktiven Code mit den entsprechenden Folgen übernommen.
Schöner wäre z.B.template <typename T> typename std::enable_if<std::is_fundamental<T>, std::ostream>::type& write_unformatted(std::ostream& os, const T& value) { os.write(&reinterpret_cast<const char&>(value), sizeof value); return os; }Damit werden automatisch erst einmal alle fundamentalen Typen erschlagen (nur für diese macht das ja einigermaßen Sinn). Für weitere Typen kann man dann geeignete Overloads anbieten (die logischerweise ohne Casts auskommen)
struct foo { std::vector<int> bar; int baz; }; template <typename T, typename A> ostream& write_unformatted(std::ostream& os, const std::vector<T, A>& v) { write_unformatted(os, v.size()); for(auto it = v.begin(); it != v.end(); ++it) write_unformatted(os, *it); return os; } ostream& write_unformatted(std::ostream& os, const foo& v) { write_unformatted(os, v.bar); write_unformatted(os, v.baz); return os; }
-
Naja, wenn du sowas meintest

-
Wenn schon auf Kleinigkeiten herum reiten, dann bitte so:
template <typename T> typename std::enable_if<std::is_fundamental<T>, std::ostream>::type& write_unformatted(std::ostream& os, const T& value) { void const* temp = static_cast<void const*>(&value); os.write(static_cast<char const*>(temp), sizeof(value)); return os; }
-
Das ist UB.
-
Ethon schrieb:
Wenn schon auf Kleinigkeiten herum reiten, dann bitte so:
template <typename T> typename std::enable_if<std::is_fundamental<T>, std::ostream>::type& write_unformatted(std::ostream& os, const T& value) { void const* temp = static_cast<void const*>(&value); os.write(static_cast<char const*>(temp), sizeof(value)); return os; }Warum? Es geht nicht darum, Dinge zu verstecken. Wenn es gefährlich (bzw. in irgenweiner Weise speziell) ist, sollte der Code das auch widerspiegeln. Umgekehrt geht es nicht an, sich diesbezgl. 100 mal zu wiederholen (gerne dann in 500-Zeilen-Monsterfunktionen). Dann wird nämlich die Aufmerksamkeit bei jeder einzelnen Zeile stark nachlassen.
-
Ich hab jediglich den Cast von reinterpret auf 2 statics geändert, was ja in der Theorie die sauberere & sichere Version ist.

-
Sieht interessant aus^^ Damit kann ich mir sicher etwas zusammenbasteln.
Was ist denn 'auto' für ein Datentyp? Ich kannte das nur als Präfix, um die Art der Speicherung anzugeben... also z.B. auto int a oder register int b ... so in dem Kontext halt...
-
Richi schrieb:
Sieht interessant aus^^ Damit kann ich mir sicher etwas zusammenbasteln.
Was ist denn 'auto' für ein Datentyp? Ich kannte das nur als Präfix, um die Art der Speicherung anzugeben... also z.B. auto int a oder register int b ... so in dem Kontext halt...Für einen C++0x Compiler (unterstützen praktisch alle schon) bedeutet es, dass er den Typ selbst aus dem Statement herleiten soll.
auto i = 1; // int auto str = "Hallo Welt"; //const char*etc. Ist halt vor allem bei Iteratortypen ein gewaltiger Vorteil, da man nicht die ewig langen Namen ausschreiben muss.
-
314159265358979 schrieb:
Ich habe doch nur ein & vergessen
Blöderweise aber an einer Stelle wo es der Compiler nicht bekritteln wird, und es erst zur Laufzeit kracht.
Bzw. wenn du Pech hast kracht es zur Laufzeit gar nicht, und es wird statt dessen irgendein Speicherbereich gelesen bzw. überschrieben, wo andere wichtige Daten stehen.
-
hustbaer schrieb:
314159265358979 schrieb:
Ich habe doch nur ein & vergessen
Blöderweise aber an einer Stelle wo es der Compiler nicht bekritteln wird, und es erst zur Laufzeit kracht.
Bzw. wenn du Pech hast kracht es zur Laufzeit gar nicht, und es wird statt dessen irgendein Speicherbereich gelesen bzw. überschrieben, wo andere wichtige Daten stehen.Deswegen 2x static_cast statt reinterpret_cast
-
Ich bin immer noch der Meinung, dass die static_cast Variante UB ist. Aber camper kennt sich da bestimmt besser aus. Und ja @hustbaer, da hast du natürlich Recht. Dafür eine eigene Funktion ist bei mehr als 1 Operation besser. Allerdings kann man dann gleich (zumindest bei std::vector) .data() verwenden.
-
314159265358979 schrieb:
Ich bin immer noch der Meinung, dass die static_cast Variante UB ist. Aber camper kennt sich da bestimmt besser aus. Und ja @hustbaer, da hast du natürlich Recht. Dafür eine eigene Funktion ist bei mehr als 1 Operation besser. Allerdings kann man dann gleich (zumindest bei std::vector) .data() verwenden.
Wieso sollte das UB sein?
static_cast castet beliebige Pointer von und zu void Pointern, was soll daran UB sein?
-
Ich meine irgendwann gelesen zu haben, dass lediglich ein cast von cv void* zu cv T* erlaubt ist, wenn der zuvor zu cv void* gecastete Zeiger ein Zeiger auf cv T* war.
-
314159265358979 schrieb:
Ich meine irgendwann gelesen zu haben, dass lediglich ein cast von cv void* zu cv T* erlaubt ist, wenn der zuvor zu cv void* gecastete Zeiger ein Zeiger auf cv T* war.
Bei POD-Typen wohl kaum relevant.

Sonst wäre der reinterpret mindestens genauso falsch.
-
Ethon schrieb:
Sonst wäre der reinterpret mindestens genauso falsch.
ist er auch. Wenn cast, dann static_cast. reinterpret_cast ist AFAIK immer implementation defined.
314159265358979 schrieb:
Ich meine irgendwann gelesen zu haben, dass lediglich ein cast von cv void* zu cv T* erlaubt ist, wenn der zuvor zu cv void* gecastete Zeiger ein Zeiger auf cv T* war.
Der cast, insbesodnere static_cast ist immer erlaubt. Der Zugriff danach aber nicht. Du darfst jeden Zeiger nach char* casten, den char Zeiger dann aber nicht verwenden. Allerdings glaube ich nicht, dass das fuer PODs UB ist, sondern nur implementation defined. (ist ja auch klar, der Standard sagt nichts ueber Byte Order aus)
-
Für reinterpret_cast gibt es imo eine Ausnahme für cv char*, die besagt, dass die Bytes da der Reihenfolge liegen müssen. Endianess wird keine vorgegeben.
-
So, mal nachgelesen, der Standard sagt folgendes zu reinterpret_cast:
When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.
Beudetet also, dass beide Varianten erlaubt und möglich sind. Dennoch ist der reinterpret_cast die direktere Methode, den Cast auszudrücken und daher meiner Meinung nach vorzuziehen.
-
Dennoch ist der reinterpret_cast die direktere Methode, den Cast auszudrücken und daher meiner Meinung nach vorzuziehen.
Naja, du hast doch gleich das Problem mit reinterpret_cast vorgemacht und einen schwer auffindbaren Fehler durch das fehlende & gebastelt.
Ich hab mir dazu mal eine Funktion ptr_cast gebaut, die das unter der Haube macht.