Seltsamer Crash, std::vector push_back



  • Hi.
    Hi 🙂
    Hab gerade ein etwas blödes Problem...

    Hier mal der Code etwas zusammengefasst:

    class State;
    class DerivedFromState : public State { };
    
    std::vector<State*> listOfStates; 
    
    void addState(State* state)
    {
        listOfStates.push_back(state);
    }
    
    addState(new DerivedFromState);
    

    Aus irgendeinem Grund crashed push_back. Woran könnte das liegen?
    Windows weist mich mit einer netten Messagebox daraufhin, dass Exception 0xc0000417 geworfen wurde, nur hilft mir das nicht weiter.

    ( http://social.msdn.microsoft.com/Forums/en-US/vsdebug/thread/2d0577ec-562a-498d-af66-0177a3f2e52c )

    Danke 🙂

    Grüße,
    Flo



  • Also wo genau passiert der Fehler? - Beim push_back selbst, oder wie?

    Hast du mal mit dem Debugger geprüft?

    Prinzipiell ist der Code korrekt.



  • Ja, bei push_back.
    Hier mal meine ganze Implementierung einer pulsierenden Finite State Machine, worin der Fehler auftritt:

    #ifndef __FSM_HPP__
    #define __FSM_HPP__
    
    #include <vector>
    #include <algorithm>
    
    namespace Navigator
    {
    	class State
    	{
    	public:
    		virtual bool			run()			{ return false; }
    		virtual bool			hasToRun()		{ return false; }
    		virtual unsigned long	getPriority()	{ return 0xFFFFFF; }
    	};
    
    	class FiniteStateMachine
    	{
    	public:
    		FiniteStateMachine()
    		{ 
    			running = false;
    		}
    
    		~FiniteStateMachine()
    		{ 
    			for(std::vector<State*>::iterator listIt = stateList_.begin(); listIt != stateList_.end(); ++listIt)
    			{
    				delete (*listIt);
    			}
    		}
    
    		void addState(State* state)
    		{
    			stateList_.push_back(state);
    			std::sort(stateList_.begin(), stateList_.end(), compareStates);
    		}
    
    		void run()
    		{
    			running = true;
    		}
    
    		void stop()
    		{
    			running = false;
    		}
    
    		void pulse()
    		{
    			if(running)
    			{
    				for(std::vector<State*>::iterator listIt = stateList_.begin(); listIt != stateList_.end(); ++listIt)
    				{
    					if((*listIt)->hasToRun())
    					{
    						if((*listIt)->run())
    							break;
    						else
    							stop();
    					}
    				}
    			}
    		}
    
    	private:
    		bool running;
    		std::vector<State*> stateList_;
    
    		static bool compareStates(State* a, State* b)
    		{
    			return(a->getPriority() < b->getPriority());
    		}
    	};
    }
    
    #endif //__FSM_HPP__
    

    Funktionalität wird durch das Überladen von State hinzugefügt.

    Und ja, der Crash tritt genau auf wenn push_back aufgerufen wird.



  • Probier mal mit einer std::list. Kommt das gleiche?


  • Mod

    Icematix schrieb:

    for(std::vector<State*>::iterator listIt = stateList_.begin(); listIt != stateList_.end(); ++listIt)
                {
                    delete (*listIt);
                }
    

    Ich sehe keinen virtuellen Destruktor.



  • camper schrieb:

    Icematix schrieb:

    for(std::vector<State*>::iterator listIt = stateList_.begin(); listIt != stateList_.end(); ++listIt)
                {
                    delete (*listIt);
                }
    

    Ich sehe keinen virtuellen Destruktor.

    Wozu einen virtuellen Destruktor?
    Die State-Klasse hat einen Standard-Destruktor der nichts macht.
    Die erbenden Klassen machen auch nichts im Destruktor.
    FiniteStateMachine wird nicht vererbt.

    Außerdem tritt das Problem ja nicht beim Löschen der Objekte sondern beim Anlegen auf.



  • Icematix schrieb:

    Wozu einen virtuellen Destruktor?

    Les' mal das hier.


  • Mod

    Icematix schrieb:

    Außerdem tritt das Problem ja nicht beim Löschen der Objekte sondern beim Anlegen auf.

    Vielleicht, aber das ist der Fehler, der mir aufgefallen ist. Abgesehen davon, hast du nicht ausdrücklich gesagt, dass es schon beim allerersten push_back knallt.
    Nebenbei scheint mir

    void addState(State* state)
            {
                stateList_.push_back(state);
                std::sort(stateList_.begin(), stateList_.end(), compareStates);
            }
    

    nicht besonders effizient zu sein, wenn - wie ich annehme - sich der Wert von getPriority wärend der Lebenszeit eines State-Objektes nict ändert, stateList_ also immer sortiert ist. Dann ist es besser, gleich die richtige Einfügestelle zu ermitteln und nicht ein komplettes sort auf den vector loszulassen

    void addState(State* state)
            {
                stateList_.insert( std::lower_bound( stateList_.begin(), stateList_.end(), state, compareStates), state );
            }
    


  • Eingefügt, geholfen hat es leider nix 😕

    Edit: @Camper: Ja, stimmt. Nur hab ich mir darüber keine Gedanken gemacht, bei sagen wir mal ~20 States ist die Rechenzeit echt vernachlässigbar. Aber gute Idee, ich ändere es gleich mal.



  • Vielleicht solltest Du mal überprüfen, was vorher so passiert. In Deinen von State abgeleiteten Objekten z.B.
    Beim push_back wird ja nur ein Pointer eingefügt. Dabei kann eigentlich nichts schief gehen. Ich schätze mal, dass Du Dir vorher irgendwo den Stack zerballerst (also nicht im gwposteten Code).



  • Tachyon schrieb:

    Vielleicht solltest Du mal überprüfen, was vorher so passiert. In Deinen von State abgeleiteten Objekten z.B.
    Beim push_back wird ja nur ein Pointer eingefügt. Dabei kann eigentlich nichts schief gehen. Ich schätze mal, dass Du Dir vorher irgendwo den Stack zerballerst (also nicht im gwposteten Code).

    Stack zerballern? Klingt abenteuerlich.
    Außerdem ist es ohne dem Funktionsaufruf absolut stabil...



  • Icematix schrieb:

    Außerdem ist es ohne dem Funktionsaufruf absolut stabil...

    Diese Aussage muss nicht stimmen. Das ist ja das furchtbare, wenn du undefiniertes Verhalten erzeugst. Es kann sehr lange gut gehen, bis du auf einmal etwas völlig harmloses (wie ein push_back) machst und dann gehts nicht mehr und du kriegst einen merkwürdigen Fehler, wie den hier.

    Ich würde auch darauf tippen, dass du irgendwo anderst etwas falsch machst. (Zugriff auf freigegebenen Speicher z.B?)



  • Habe das Problem eingegrenzt.
    Könnte es daran liegen, dass mein FiniteStateMachine-Objekt ein statisches Objekt ist und ich addState im (natürlich nicht-statischen) Konstruktor aufrufe?

    Hier mal eine grobe Übersicht der Klasse, in welcher ich es nutze (Ist ne Singleton) :

    Klasse:

    class Foobar
    	{
    	public:
    
    		...
    
    		static Foobar*		getInstance();
    		static void		destroyInstance();
    
    		....
    
    	private:
    
    		.....
    
    		//FSM
    		static Navigator::FiniteStateMachine fsm;
    
    		//Pointer to the instance
    		static Foobar* instance;
    
    		Foobar();
    		~Foobar();
    
    		....
    	};
    

    Konstruktor:

    Foobar::Foobar()
    	{
    		...
    
    		//Set up the FSM
    		fsm.addState(new IdleState);
    
    		...
    	}
    

    Wenn ich ein neues FiniteStateMachine-Objekt im Konstruktor erstelle und diesem States hinzufüge, crashed es nicht.

    Mache ich was ganz offensichtlich falsch?



  • Sorry für den Doppelpost.
    Hab die FSM jetzt zeitweise nicht-static gemacht (musste sämtlich Aufrufe in statischen Funktionen herauskommentieren) und es gibt keinen Crash mehr !

    Wo könnte das Problem sein, bin mit meinem Latein am Ende. Benutze statische Objekte anderer Klassen auf die selbe Art und es gab nie Probleme 😕



  • Könnte es daran liegen, dass mein FiniteStateMachine-Objekt ein statisches Objekt ist und ich addState im (natürlich nicht-statischen) Konstruktor aufrufe?

    So weit ich das verstehe, ist das völlig unbenklich...

    und es gibt keinen Crash mehr

    denk immer daran: undefiniert bleibt undefiniert...
    Das Problem kann wo ganz anders liegen! Das ist eben die sch**** an undefiniertem Verhalten - man kann im Grunde genommen noch mal nen neues Projekt anfangen, wenn man nicht weiß, wo man es fabriziert hat...

    bb



  • unskilled schrieb:

    man kann im Grunde genommen noch mal nen neues Projekt anfangen, wenn man nicht weiß, wo man es fabriziert hat...

    Oder ein paar Nächte lang debuggen. Wenn man den Fehler dann hat und merkt, wie dämlich der war, dann ist das der Moment, wo man begreift, wie wichtig es ist definiertes Verhalten zu haben und alles undefinierte einfach mal misstrauisch anzuschauen.



  • Naja, habe absolut keine Lust mehr auf den Scheiß und habe mich zu einer Alternativlösung entschieden:

    Da ich sowieso große Teile des Programm scriptbar machen möchte, wird jetzt auch das auf Scripts umgewälzt.
    Wird zwar zwangsläufig darauf hinauslaufen dass nur das Allernötigste in C++ geschrieben wird (Low-Level Hooks etc), aber ich denke Performancemäßig wird Python schon ok sein. 😉


Anmelden zum Antworten