erase-Command für UndoManager



  • Hallo,
    ich benutze in einem Projekt einen UndoManager. Wie so etwas aussieht könnt ihr euch sicher vorstellen. Nun brauche ich ein Kommando, welches auf Containern operiert und erase ausführt bzw. rückgängig macht. Leider scheinen dabei Iteratoren ungültig zu werden o.ä., so dass nach einer Abfolge von Kommandos irgendwann ein Crash auftritt. Es hängt jedenfalls definitiv mit dem EraseCommand zusammen.

    template<typename Type, template<typename, typename> class Container>
    class Erase : public Command
    {
    	typedef Container<Type*, std::allocator<Type*> > ContainerType;
    	typedef typename ContainerType::iterator Iterator;
    	ContainerType& container;
    	Type* val;
    	Iterator pos;
    
    public:
    	Erase(Iterator const& pos, ContainerType& container)
    		: val(*pos), pos(pos), container(container) {}
    
    	virtual ~Erase()
    	{
    		if(isInUndoStack())
    			delete val;
    	};
    
    	bool exec()
    	{
    		container.erase(pos++);
    		return true;
    	}
    
    	void undo()
    	{
    		pos = container.insert(pos, val);
    	}
    };
    

    Im Grunde besteht das Problem darin, etwas aus einem Container (in meinem Fall std::list) zu löschen und später an genau dieser Stelle wieder einzufügen, ohne dass die Iteratoren ungültig werden.

    Vielleicht hat ja jemand von euch eine Idee?

    Viele Grüße!



  • Beim Löschen in list's wird eigentlich nur das Ziel ungültig. Aber wenn du zwischendurch weitere Elemente gelöscht (und wiederhergestellt hast), könnte das auch deinen Iterator pos betreffen. Als Alternative könntest du den Index des gelöschten Objekts notieren und beim Wiederherstellen die richtige Position abzählen.

    (aber dazu ist list<> eher ungeeignet)

    PS: Ich hoffe, du achtest immer darauf, daß jedes Kommando nur einmal (und dann in umgekehrter Reihenfolge) rückgängig gemacht wird 😉



  • Hmm, ich glaube, dass ich dann um einen vector wohl nicht herumkomme. Denn nat. will ich auch mehrere Objekte löschen und wiederherstellen können.



  • Ich sagte nicht, daß es mit list nicht geht, list ist "nur" ungeeignet, weil es keine Random-Access-Iteratoren hat. Du kannst aber immernoch advance() verwenden, um das i-te Element deiner Liste zu erreichen (im Gegensatz zum vector benötigt das jedoch lineare Zeit).

    Damit hängt es wohl von deiner konkreten Anwendung ab, ob vector oder list günstiger ist - vector benötigt i.a. länger zum Löschen der Elemente (alles hinter der Position muß umkopiert werden), list zum Wiederherstellen (durchhangeln zur richtigen Position).



  • stephan.m schrieb:

    Hmm, ich glaube, dass ich dann um einen vector wohl nicht herumkomme. Denn nat. will ich auch mehrere Objekte löschen und wiederherstellen können.

    Genau umgekehrt. Es ist generell keine gute Idee Iteratoren eines "dynamischen" vectors langfristig zu speichern.

    D.h. du wendest dich std::list zu oder überlegst dir für vectoren eine andere Strategie (z.B. Offset statt Iterator speichern).


Anmelden zum Antworten