Objekt im Speicher verschieben ; Speicherabbild erstellen



  • Hallo,

    viele Betriebssysteme bieten einen sogenannten "Ruhezustand" an und das beschäftigt mich zur Zeit ein wenig.
    Es muss daher möglich sein, ein Objekt in eine Datei zu schreiben und wieder zu laden. Wenn ich einen Zeiger zu einem C++-Objekt habe, kann ich dieses Objekt mit fwrite() in eine Datei schreiben. Mit fread() lässt sich das ganze wieder in den Heap transportieren. So, wie kann ich jetzt das Objekt wieder herstellen? Ist für derartige Zwecke std::reinterpret_cast geeignet?

    Achja, lässt sich das auch mit Objekte im Stack durchführen?

    void Klasse1::abc()
    {
      int k = 5;
      int *p = &k;
    
      // Datei öffnen und das Ziel von p hineinschreiben
      // ...
      // Datei schließen
    
      int k_neu;
      int *p2 = &k_neu;
      // Datei wieder öffnen und das Ziel von p2 füllen
      // ...
      // Datei schließen
    }
    

    Als nächstes Interessiert mich noch das Verschieben von vorhanden Objekten. Hierzu bietet C die Funktion memmove() bzw. memcopy(). So, wie muss ich hier vorgehen, ohne dass ich den Standard bzw. das RTTI verletzte?
    - Object mit new erzeugen
    - mit memmove() den Speicher verschieben
    - alten Zeiger nicht mehr verwenden bzw. auf NULL setzen
    - den neuen Speicher mit std::reinterpret_cast auslesen

    Funktioniert das so zu 100% oder muss ich memcopy nehmen, da ich sonst die Laufzeitinformationen des RTTI zerstöre?

    Über eine Anwort würde ich mich sehr freuen.

    Gruß
    Thomas



  • Irgendwie scheint mir das ein gefrickel.

    Bestimme ein (allg.) Format wie Du deine Objekte serialisieren / deserialisieren möchtest (als ascii, xml, etc.) und impl. Mechanismen dafür.

    Baue eine Zwischenlayer ein und verlasse dich nicht auf das C++ Objekt Layout (welches Kompiler- und Platformabhängig ist).

    Simon



  • Objekte serialisieren kann schwierig sein, wenn diese Zeiger auf andere Objekte enthalten, die wiederum auf was anderes verweisen usw. Echte tiefe Kopien von objekten sind in C++ allgemein nicht möglich, so wie etwa in Java und anderen SPrachen, die sehr viele dynamische Laufzeitinformationen enthalten.



  • Siassei schrieb:

    viele Betriebssysteme bieten einen sogenannten "Ruhezustand" an und das beschäftigt mich zur Zeit ein wenig.
    Es muss daher möglich sein, ein Objekt in eine Datei zu schreiben und wieder zu laden.

    Das Betriebssystem macht das aber auf einer anderen Ebene: der komplette Zustand des Computers wird abgespeichert und wieder geladen. Jedes Byte wird an der gleichen Adresse wie vor dem Speichern platziert.

    Um das mit deinem Code umzusetzen, bräuchtest du die Unterstützung des Betriebssystems, um ein Gesamtabbild des Speicherbereichs deines Programms inkl. der Laufzeitumgebung zu speichern, und wieder an die gleichen Adressen zu laden.

    Du kannst das auf Objekt-Ebene in C++ nicht realisieren, ohne die exakten Details des internen, compilerspezifischen Objektlayouts zu kennen. Die bräuchtest du, um dir die Adressen nach dem Laden wieder zurecht zu biegen, und die werden nicht vom C++-Standard definiert.

    Du hast es viel einfacher und portabler, wenn du deine Serialisierung so machst wie alle anderen; unabhängig vom Objektlayout, jedes Feld einzeln.



  • Irgendwie scheint mir das ein gefrickel.

    Bestimme ein (allg.) Format wie Du deine Objekte serialisieren / deserialisieren möchtest (als ascii, xml, etc.) und impl. Mechanismen dafür.

    Mir geht es nicht darum, einen "schlechten" Serialisierungsalg. oder ähnliches umzusetzen, sondern die Möglichkeiten von C++ (C++0x) in Kombination von C zu ergründen. In wie fern eine Mischung gut ist, lasse ich mal im Raum stehen.

    Ein hohes interesse habe ich für das Verschieben von Objekten

    Hierzu bietet C die Funktion memmove() bzw. memcopy(). So, wie muss ich hier vorgehen, ohne dass ich den Standard bzw. das RTTI verletzte?
    - Object mit new erzeugen
    - mit memmove() den Speicher verschieben
    - alten Zeiger nicht mehr verwenden bzw. auf NULL setzen
    - den neuen Speicher mit std::reinterpret_cast auslesen

    Funktioniert das so zu 100% oder muss ich memcopy nehmen, da ich sonst die Laufzeitinformationen des RTTI zerstöre?

    Wie sieht die korrekte Verwendung von std::move aus?



  • Schau dir mal Boost.Serialization an. Das funktioniert sogar mit verschachtelten Smart-Pointern.

    Gruß
    Don06



  • Siassei schrieb:

    Ein hohes interesse habe ich für das Verschieben von Objekten

    Hierzu bietet C die Funktion memmove() bzw. memcopy(). So, wie muss ich hier vorgehen, ohne dass ich den Standard bzw. das RTTI verletzte?

    Darfst du nur für PODs benutzen. Die Funktionen kopieren nur blind den Speicherinhalt von einer Stelle an eine andere. Wenn du ein Nicht-POD-Objekt damit kopierst, ist das Ergebnis undefiniert.

    Funktioniert das so zu 100% oder muss ich memcopy nehmen, da ich sonst die Laufzeitinformationen des RTTI zerstöre?

    Funktioniert nicht. RTTI ist irrelevant, weil das gesamte Ergebnis undefiniert ist.



  • Siassei schrieb:

    Ist für derartige Zwecke std::reinterpret_cast geeignet?

    Nein. reinterpret_cast (ohne "std::", das ist ein Schlüsselwort!) ist ein Cast-Operator, der - wie der Name schon sagt - Speicher als Bitmuster eines bestimmten Typen interpretieren kann. In vielen Fällen ist der Einsatz ungerechtfertigt und führt zu undefiniertem Verhalten.

    Siassei schrieb:

    Als nächstes Interessiert mich noch das Verschieben von vorhanden Objekten. Hierzu bietet C die Funktion memmove() bzw. memcopy(). So, wie muss ich hier vorgehen, ohne dass ich den Standard bzw. das RTTI verletzte?
    - Object mit new erzeugen
    - mit memmove() den Speicher verschieben
    - alten Zeiger nicht mehr verwenden bzw. auf NULL setzen
    - den neuen Speicher mit std::reinterpret_cast auslesen

    Wie schon angetönt wurde, darfst du Objekte von Typen, die keine PODs sind, nicht byteweise verschieben oder kopieren. Hier habe ich vor einiger Zeit eine Diskussion diesbezüglich gestartet.

    Warum willst du Speicher verschieben? Oft erreicht man das gewünschte Verhalten durch eine zusätzliche Indirektion. Konkret heisst das, du hast einen Zeiger auf ein Objekt, und statt das Objekt zu zerstören und andernorts wieder zu konstruieren überträgst du den Zeiger. Im Zusammenhang mit Move-Semantik kannst du dir auch einmal std::auto_ptr anschauen. In C++0x gibts zusätzlich RValue-Referenzen.



  • general bacardi schrieb:

    Objekte serialisieren kann schwierig sein, wenn diese Zeiger auf andere Objekte enthalten, die wiederum auf was anderes verweisen usw. Echte tiefe Kopien von objekten sind in C++ allgemein nicht möglich, so wie etwa in Java und anderen SPrachen, die sehr viele dynamische Laufzeitinformationen enthalten.

    Man kann die Objekte, die an den Pointern hängen ebenfalls Serialisierbar machen. In der Serializefunktion wird dann in die entsprechende Funktion des Memberobjekts gesprungen. Ist überhaupt kein Problem.



  • In C++0x gibts zusätzlich RValue-Referenzen.

    Hier Blicke ich nicht ganz durch.

    A a();
    
    // Worin Unterscheiden sich diese Zeilen, oder sind sie alle gleich?
    // Was passiert mit der Variable a nach dem Verschieben? a == NULL?
    A b = std::move(a);
    A&& c = a
    A&& d = std::move(a);
    // benötige ich std::move überhaupt oder ist dies Werkzeug für ältere Klassen?
    // Eine neuere wäre für mich eine, die einen RValue-Konstruktor bestitzt.
    // Oder bekommen alle Klassen automatisch einen RValue-Konstruktor?
    

    Warum willst du Speicher verschieben?

    Speicher verschieben? Du meinst sicherlich ein Objekt vom Speicherplatz A zum Platz B.

    Warum? Es gibt keinen konkreten Anwendungsfall. Alleine aus Interesse an C++0x und den Möglichkeiten in C++. Ich arbeite mich in das Pool-Concept ein wenig ein und suche nach Möglichkeiten, einer Fragmentation entgegen zu wirken. Hierzu muss ich ein Objekt verschieben. Oder ein Objekt aus dem Pool A in den Pool B verschieben, oder aus dem Pool p in den Heap. So langsam glaube ich, dass rvalue und std::move das Richtige sind. Leider komme ich mit den Erklärungen im Web (eigentlich nur eine und tausendmal abgeschrieben) nicht ganz so klar. Siehe oben

    A& a = pool->create<A>();
    B& b = pool->create<B>();
    A& c = pool->create<C>();
    
    pool->free(b);
    // ordne den Speicher
    pool->collect();
    
    //...
    
    // Zerstöre Pool und alle beinhaltete Objecte
    delete pool;
    


  • schmuessla schrieb:

    general bacardi schrieb:

    Objekte serialisieren kann schwierig sein, wenn diese Zeiger auf andere Objekte enthalten, die wiederum auf was anderes verweisen usw. Echte tiefe Kopien von objekten sind in C++ allgemein nicht möglich, so wie etwa in Java und anderen SPrachen, die sehr viele dynamische Laufzeitinformationen enthalten.

    Man kann die Objekte, die an den Pointern hängen ebenfalls Serialisierbar machen. In der Serializefunktion wird dann in die entsprechende Funktion des Memberobjekts gesprungen. Ist überhaupt kein Problem.

    Er meinte, dass Reflection in C++ nicht standardmäßig dabei ist. Mit einer Reflection-API kannst du das alles automatisieren.



  • Siassei schrieb:

    Speicher verschieben? Du meinst sicherlich ein Objekt vom Speicherplatz A zum Platz B.

    Ja, "Speicherinhalt" wäre besser formuliert gewesen. 🙂

    Siassei schrieb:

    Warum? Es gibt keinen konkreten Anwendungsfall. Alleine aus Interesse an C++0x und den Möglichkeiten in C++. Ich arbeite mich in das Pool-Concept ein wenig ein und suche nach Möglichkeiten, einer Fragmentation entgegen zu wirken. Hierzu muss ich ein Objekt verschieben. Oder ein Objekt aus dem Pool A in den Pool B verschieben, oder aus dem Pool p in den Heap. So langsam glaube ich, dass rvalue und std::move das Richtige sind.

    Du solltest bedenken, dass die RValue-Referenzen aus C++0x nicht konzipiert sind, Objekte physikalisch zu verschieben. Vielmehr stellen sie besondere Regeln bereit, die Optimierungen erlauben, zum Beispiel bezüglich Umgang mit temporären Objekten und Elimination unnötiger Kopien.

    Für deinen Anwendungsfall scheinen mir wie gesagt Zeiger besser geeignet. Oder du machst etwas mit swap() , das besonders bei grösseren Objekten wahnsinnig effizient sein kann.



  • theta schrieb:

    Irgendwie scheint mir das ein gefrickel.

    Bestimme ein (allg.) Format wie Du deine Objekte serialisieren / deserialisieren möchtest (als ascii, xml, etc.) und impl. Mechanismen dafür.

    Baue eine Zwischenlayer ein und verlasse dich nicht auf das C++ Objekt Layout (welches Kompiler- und Platformabhängig ist).

    Simon

    Es graut mich hier gleich wieder von ASCII und XML zu lesen!
    Wieso kommen so viele Leute automatisch auf die Idee irgendwelche Daten als Text interpretieren zu müssen?!

    Die grundsätzliche Idee des Themas interessiert mich auch sehr.
    Es währe extrem nützlich wenn alle Datentypen der Standardbibliothek in binäre Datenblöcke ausgegelesen und daraus wieder interpretiert werden könnten. Natürlich müsste man dann für benutzerdefinierte Typen in den Strukturen das dann auch definieren.



  • sqrt(-1) schrieb:

    Es graut mich hier gleich wieder von ASCII und XML zu lesen!
    Wieso kommen so viele Leute automatisch auf die Idee irgendwelche Daten als Text interpretieren zu müssen?!

    Warum denn nicht? - Warum sollte man es binär machen? - Das bringt nur viele Probleme und wenn man die geringere Speicherkapazität nicht wirklich braucht, dann fährt man besser, wenn man was Textbasiertes hat.



  • sqrt(-1) schrieb:

    Es graut mich hier gleich wieder von ASCII und XML zu lesen!
    Wieso kommen so viele Leute automatisch auf die Idee irgendwelche Daten als Text interpretieren zu müssen?!

    In welche Form man die Daten letztendlich bringt, ist doch nebensächlich und hängt letztendlich davon ab, was man damit machen will. Textformate sind oft erste Wahl, weil sie leicht zu debuggen sind und man sich nicht mit Problemen wie Endianess oder Datenwortbreiten rumschlagen muss.



  • drakon schrieb:

    Warum denn nicht? - Warum sollte man es binär machen? - Das bringt nur viele Probleme und wenn man die geringere Speicherkapazität nicht wirklich braucht, dann fährt man besser, wenn man was Textbasiertes hat.

    Wieso? Welche Probleme?

    Nur weil es für XML viele Werkzeuge existieren, begründet sich nicht der Sinn die Daten als Text interpretieren zu müssen! Dass heutzutage selbst http-Daten letztendlich kaum noch auf Text hinauslaufen muss man da garnicht mal als Argument vorbringen.



  • sqrt(-1) schrieb:

    Nur weil es für XML viele Werkzeuge existieren, begründet sich nicht der Sinn die Daten als Text interpretieren zu müssen! Dass heutzutage selbst http-Daten letztendlich kaum noch auf Text hinauslaufen muss man da garnicht mal als Argument vorbringen.

    Probleme: Einfache Lesbarkeit/Veränderung ohne einen zusätzlichen Editor. Wenn man gewisse Dateien für verschiedene Systeme haben will, dann kann man diese nicht gleich speichern/laden, sondern muss auf Sachen, wie z.B Alignment.

    Gegenfrage: Warum sollte ich etwas binär speichern, wenn das speichern der Daten in Textform viel einfacher und portabler ist?



  • sqrt(-1) schrieb:

    Wieso? Welche Probleme?

    Zum Beispiel ist Portabilität nahezu unmöglich, du musst selbst auf dem gleichen Compiler sehr aufpassen (Alignment & Co.), kleinste Änderungen an an einer Klasse können die gespeicherten Daten unbrauchbar machen, Debugging ist massiv schwieriger.



  • Registrierter Troll schrieb:

    In welche Form man die Daten letztendlich bringt, ist doch nebensächlich und hängt letztendlich davon ab, was man damit machen will.

    Ich sehe das anders wenn man die Petawatt an Energie betrachtet, die nur deswegen anfallen weil Daten und Strukturen in Textformaten zwischengespeichert werden.

    Textformate sind oft erste Wahl, weil sie leicht zu debuggen sind und man sich nicht mit Problemen wie Endianess oder Datenwortbreiten rumschlagen muss.

    Das Textformate "leicht zu debuggen sind" ist doch eine absolute Nullaussage. Klar kann ich eine Konfiguration.txt lesen und eine Konfiguration.dat nicht. Bei OfficeDatei.xml ist es wieder absolut hinfällig.

    Probleme wie Endianess und Datenwortbreite sind kein Grund für ein Textformat.



  • sqrt(-1) schrieb:

    Ich sehe das anders wenn man die Petawatt an Energie betrachtet, die nur deswegen anfallen weil Daten und Strukturen in Textformaten zwischengespeichert werden.

    Denk mal an die vielen Probleme, die behoben oder umgangen werden müssten, wenn alles nur noch binär gespeichert würde (welche, wurde ja genannt). Und überlege dir, ob man für den Mehraufwand, ein halbwegs portables Binärformat zu realisieren, auch Energie braucht.

    sqrt(-1) schrieb:

    Probleme wie Endianess und Datenwortbreite sind kein Grund für ein Textformat.

    Das kannst du sicher begründen.


Anmelden zum Antworten