Objektstatus speichern und wiederherstellen


  • Mod

    Hi,

    vermutlich denke ich gerade wieder viel zu kompliziert. Ich habe ein Objekt welches einen Teil seines inneren Zustands auf Kommando speichern und wieder herstellen soll. In etwa so:

    My_class my_object;
    
    // ...
    
    my_object.save_state();
    // Jetzt werden die Werte verändert und ein paar Berechnungen durchgeführt
    if (changes_not_accepted) my_object.restore_state();
    

    Das Problem: Es gibt hunderttausende dieser Objekte, irgendwann vielleicht auch mal hunderte von Millionen, ein paar zig Bytes Zusatzspeicher pro Objekt würde da schon reinhauen.

    Deshalb die Idee von mir, den Objektstatus in einer statischen Membervariable zwischenzuspeichern.
    Die zwei Nachteile die mir einfallen:
    a) Nicht threadparallelisierbar. Aber das wird wohl nie passieren, weil das Programm bereits auf Prozessebene parallelisiert ist.
    b) Verlust der Lokalität. Das Programm ist zwar zeitkritisch, aber die Berechnungen zwischendurch sind es, die reinhauen werden, nicht zwei Cachemisses am Anfang und am Ende der Rechnung.

    Übersehe ich da irgendeine einfachere Lösung oder ein Problem an meiner Lösung?



  • Klingt ja erstmal nach Memento. Da mal nach Implementierungen geguckt?
    Die Objekte scheinen ja sehr klein zu sein. Was spricht gegen 'einfach kopieren' und zurückkopieren?



  • Also wenn da eine statische Variable deinen Anforderungen genügt, dann könntest du doch auch einfach eine lokale Variable nehmen..

    state temp = my_object.get_state();
    // Jetzt werden die Werte verändert und ein paar Berechnungen durchgeführt
    if (changes_not_accepted) my_object.set_state(temp);
    

    Die Objekte brauchen ja keine in dem Fall den Status nicht immer, wenn ich das richtig sehe.


  • Mod

    brotbernd schrieb:

    Klingt ja erstmal nach Memento. Da mal nach Implementierungen geguckt?
    Die Objekte scheinen ja sehr klein zu sein. Was spricht gegen 'einfach kopieren' und zurückkopieren?

    Die Objekte sind polymorph und die Daten die gespeichert werden sind jeweils unterschiedlich. Ich fände es umstandlich, wenn das Programm erstmal rausbekommen müsste, welche Art von Daten es zwischenspeichern soll. Virtual typedefs gibts ja leider nicht. Kann man Unterklassen virtuell machen?

    Was mir jedoch als Nachteil zu meiner Methode eingefallen ist, ist dass der Anwender (der zwar im Moment ich bin, aber das kann sich ja auch mal ändern) eine Menge Verantwortung hat. Macht man

    object1.save();
    object2.save();
    object1.restore();
    

    ginge das ganz gewaltig schief. Könnte man jedoch mit ein paar Metadaten und ein paar Assertions abfangen 😕



  • Auf der Festplatte speichern oder im RAM einen Zustand festhalten?

    template<typename T>
    class StorableObjectListElement{
    public:
    	StorableObjectElement(const StorableObjectListElement<T>& next) : next(&next), t(next.t){
    	}
    
    	StorableObjectElement(const T& t) : next(NULL), t(t){
    	}
    
    	T& getObject(){
    		return t;
    	}
    
    	StorableObjectListElement<T>* getNext(){
    		return next;
    	}
    
    private:
    	StorableObjectListElement<T>* next;
    	T t;
    };
    
    template<typename T>
    class StorableObject{
    public:
    	StorableObject(const T& t) : first(new StorableObjectElement<T>(t)){
    	}
    
    	T& getObject(){
    		first.getObject();
    	}
    
    	void save(){
    		first = new StorableObjectListElement<T>(*first);
    	}
    
    	void restore(){
    		StorableObjectListElement<T>* del = first;
    		first = first.getNext();
    		delete del;
    	}
    
    private:
    	StorableObjectListElement<T>* first;
    
    };
    

    Was spricht gegen so eine Lösung?
    Also eigentlich nur ein Stack...
    Weniger als einen zusätzlichen Zeiger pro Revision wirst du ohne umkopieren wohl
    nicht hinkriegen.
    Hier hast du 1 pro Revision und 1 pro Objekt.

    Welchen Vorteil bietet dir denn eine statische member-Variable?
    Du erkaufst dir den gesparten Speicherplatz durch eine Umkopier-Operation.
    Während des Umkopieren wird es aber RAM-technisch noch teurer.


  • Mod

    CSpille schrieb:

    Auf der Festplatte speichern oder im RAM einen Zustand festhalten?

    Im RAM.

    // ...
    

    Was spricht gegen so eine Lösung?
    Also eigentlich nur ein Stack...
    Weniger als einen zusätzlichen Zeiger pro Revision wirst du ohne umkopieren wohl
    nicht hinkriegen.
    Hier hast du 1 pro Revision und 1 pro Objekt.

    Das wäre gut und schön, aber die Datentypen sind alle unterschiedlich. Außerdem: Warum Stack selbst implementieren?

    Welchen Vorteil bietet dir denn eine statische member-Variable?

    Keinen, außer das es eine von zwei Lösungen ist die mir bisher eingefallen sind. Die andere wäre dynamische Allokation von Zwischenspeicher durch das Objekt. Dann entfiele das Problem, dass man auf die richtige Reihenfolge achten muss, auf Kosten eines new/delete Paares und 8 Bytes pro Instanz für einen Pointer. Diese Nachteile müsste ich abwägen gegen die static Variante und tendiere eher zum static-Member. Oder es kommt noch die geniale Lösung an die ich nicht denke. Vielleicht ein Stack mit variablem Datentyp? Werde ich mal versuchen, wie man sowas bauen könnte und was das kosten würde.

    Du erkaufst dir den gesparten Speicherplatz durch eine Umkopier-Operation.
    Während des Umkopieren wird es aber RAM-technisch noch teurer.

    Verstehe ich nicht. Kannst du das mal erklären?



  • Ein Stack ist vielleicht ungeeignet, weil man nicht unbedingt in der umgekehrten Reihenfolge wiederherstellen will, in der gesichert wurde. Oder will man das?

    Was ist mit drakons Variante? Besteht da das Problem darin, dass der Status auch polymorph ist? Dann müsstest du wahrscheinlich klonen. In Anbetracht der Tatsache, dass du aber so oder so zwei Stati speichern müsstest und (falls diese tatsächlich polymorph sind) auch zur Laufzeit dispatchen müsstest, fällt mir keine wirklich bessere Methode ein. Zumindest keine allgemeingültige... Lediglich die Unterschiede zum momentanen Status zu speichern lohnt sich nicht?

    Was man sehrwahrscheinlich tun könnte, wäre die Allokationen und Deallokationen beschleunigen, indem man sich an häufig benötigten Save/Restore-Mustern orientiert.


  • Mod

    Nexus schrieb:

    Ein Stack ist vielleicht ungeeignet, weil man nicht unbedingt in der umgekehrten Reihenfolge wiederherstellen will, in der gesichert wurde. Oder will man das?

    So wie es jetzt benutzt wird, hat man eigentlich nur den Fall, das genau ein Objekt gespeichert und wiederhergestellt wird, erst danach kommt die nächste Instanz dran. Da reicht die static-Variante. Aber mir wäre es lieber wenn das für die Zukunft nicht so eingeschränkt oder wenn doch, dann zumindest irgendwie abgesichert gegen Fehlbenutzung wäre.

    Was ist mit drakons Variante? Besteht da das Problem darin, dass der Status auch polymorph ist? Dann müsstest du wahrscheinlich klonen. In Anbetracht der Tatsache, dass du aber so oder so zwei Stati speichern müsstest und (falls diese tatsächlich polymorph sind) auch zur Laufzeit dispatchen müsstest, fällt mir keine wirklich bessere Methode ein. Zumindest keine allgemeingültige... Lediglich die Unterschiede zum momentanen Status zu speichern lohnt sich nicht?

    Ja, der Status selbst ist polymorph. Die Idee mit dem Abspeichern des Unterschieds finde ich gut. Es handelt sich nämlich beim Status konkret um eine ganze Reihe double-Werte, welche mittels einer fixen Anzahl anderer double-werte modifiziert werden. Dies könnte ich ganz einfach zwischenspeichern. Ich werde morgen mal nachrechnen, ob alle Operationen die da passieren in Fließkommaarithmetik sauber rückgängig gemacht werden können.

    Was man sehrwahrscheinlich tun könnte, wäre die Allokationen und Deallokationen beschleunigen, indem man sich an häufig benötigten Save/Restore-Mustern orientiert.

    Auch eine gute Idee, kombiniert sehr hübsch die static-Membermethode mit der dynamischen Speicherreservierungsmethode. Ich könnte vom Anwender verlangen, dass er einen Brocken Speicher mit einer Mindestgröße zur Verfügung stellt und das Objekt speichert dann seine Daten auf seine Weise da rein. Zum Wiederherstellen übergibt man dem Objekt dann den entsprechenden Pointer. Da das Objekt ja selber weiß in welcher Form es welche Daten hinterlegt hat, gibt es keine Probleme. Zudem kann der Anwender auch mehrere Speicherbereiche reservieren, wenn er mehrere Objekte gleichzeitig speichern will. Und man muss dazu den Pointer noch nicht einmal im Objekt selber speichern, sondern dies den Anwender machen lassen.

    Ich glaube das ist es, wonach ich gesucht habe. Ich sehe die Vorteile aller bisherigen Lösungen vereint, ohne ihre Nachteile. 🙂

    👍


Anmelden zum Antworten