Eigene Klassen, die Pointer enthalten in Binary-Datei speichern?



  • 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.


  • Mod

    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.



  • Wenn du reinterpret_cast willst, dann sag auch reinterpret_cast und nicht static_caststatic_cast.



  • 314159265358979 schrieb:

    Wenn du reinterpret_cast willst, dann sag auch reinterpret_cast und nicht static_caststatic_cast.

    du willst immer die Methode, die den defensiveren programmierstil ermoeglicht ->static_cast.



  • Ich will die Methode, die möglichst direkt ausdrückt was ich will, und das ist der reinterpret_cast. Der ptr_cast wäre auch okay, wahrscheinlich sogar die beste Lösung.


Anmelden zum Antworten