Zufällige Abstürze



  • ok, ich hab mir das noch mal angeschaut. Es sind glaub ich noch 2 Fehler drin. Denn wenn ich nichts mache, stürzt das Programm nicht ab, erst beim Ende. Das müsste denk ich mal ein Heap-Fehler sein, denn es gibt eine Zugriffsverletzung in folgender Zeile:

    for(int a = 0; a != frames; a++)

    Sobalb ich Dinge mit der Maus machen stürzt das Programm in spätestens 30 Sekunden ab.

    Ich hab jetzt fast alles auskommentiert, und jetzt funktioniert es (ist jetzt eigentlich nur noch die Hauptschleife mit konstanten framerate).

    Sieht dann so aus (ich lass jetzt mal die init routinen weg):

    volatile int timercounter = 0;
    int counter = 0;

    Game::Game()
    {
    	//vs = new VirtualScreen(3000,3000);  //***
    }
    void Game::Run()
    {
    	int maxSkip = 4;
    	int Skip = 0;
    	install_int_ex(timerupdater,BPS_TO_TIMER(60));
    	LOCK_VARIABLE(timercounter);
    	LOCK_FUNCTION(timerupdater);
    	while(!key[KEY_ESC])
    	{
    		Skip = 0;
    		if(timercounter > 0)
    		{
    			while(timercounter>0)
    			{
    				--timercounter;
    				++Skip;
    				if(Skip >= maxSkip)
    				{
    					timercounter = 0;
    					Skip = 0;
    					std::cout << "overflow\n";
    				}
    				if(counter++%60 == 0)
    				{
                                        printf("Time: %i\n",counter/60);   
                                    }
    				//Update
    				//vs->Update();  // ***
    
    				//---------------
    				//Drawing
    				clear_to_color(buffer[actBuf],counter);
    				show_video_bitmap(buffer[actBuf]);
    				actBuf = 1 - actBuf;
    				//----------------
    			}
    
    		}
    		else
    			rest(5);
    
    	}
    }
    
    static void timerupdater()
    {
        timercounter++;
    }   
    END_OF_FUNCTION(timerupdater)
    

    Sobalb ich die mit den Sternen markierten Zeilen entkommentiere, stürzt das Programm ab, wenn man 2 minuten nach dem Start ein paar Maustasten drückt.

    Hier ist noch der VirtualScreen Code:

    In VirtualScreen.cpp

    #define VIRTUALSCREEN_RAND 100
    #define VIRTUALSCREEN_SPEED 5
    
    VirtualScreen::VirtualScreen(int w,int h)
    {
    	this->w = w;
    	this->h = h;
    	x = y = 0;
    }
    
    VirtualScreen::~VirtualScreen()
    {}
    int VirtualScreen::ToX(int X)
    {
    	return X - x;
    }
    int VirtualScreen::ToY(int Y)
    {
    	return Y - y;
    }
    void VirtualScreen::Update()
    {
    	if(mouse_x < VIRTUALSCREEN_RAND)
    		x -= VIRTUALSCREEN_SPEED;
    	if(mouse_x > SCREEN_W - VIRTUALSCREEN_RAND)
    		x += VIRTUALSCREEN_SPEED;
    	if(mouse_y < VIRTUALSCREEN_RAND)
    		y -= VIRTUALSCREEN_SPEED;
    	if(mouse_y > SCREEN_H - VIRTUALSCREEN_RAND)
    		y += VIRTUALSCREEN_SPEED;
    }
    

    In VirtualScreen.h

    class VirtualScreen
    {
    public:
    	VirtualScreen(int w, int h);
    	~VirtualScreen();
    	int w, h, x,y;
    	int ToX(int X);
    	int ToY(int Y);
    	void Update();
    };
    

    Die Klasse war die letzte, die ich als Fehleranfällig glaubte.
    Deswegen hab ich auch als letztes entkommentiert. Außerdem ist sie sehr wichtig für alle Zeichenroutinen.



  • Du solltest weniger globale Variablen verwenden, die sind nämlich ziemlich fehleranfällig und erschweren das Debugging enorm. Ausserdem könnte es helfen, wenn du auf leicht höherer Abstraktionsebene programmieren würdest. Zum Beispiel könntest du rohe Arrays durch std::tr1::array oder boost::array ersetzen, die im Debug-Modus die Indizes prüfen. Oder die Makros LOCK_VARIABLE , LOCK_FUNCTION und END_OF_FUNCTION kommen mir auch suspekt vor, was tun die genau?

    Hast du ausserdem mal mit dem Debugger geschaut, ob beim Absturz alle umliegenden Variablen korrekte Werte besitzen?



  • Warum globale veriablen gefährlich sind weiß ich nicht.

    Die Makros sind von Allegro. Ich glaube, die bringen einen kleinen geschwindigkeitsschub. Genau weiß ich das aber nicht. Steht halt so in der Dokumentation.
    Ich hab die Makros mal entfernt, es waren 4 min ohne Absturz, aber als ich es dann minimierte stürzte es auch ab.
    Ich hab schon erlebt,dass ALLEGRO abstürzt wenn es zu wenig zu tun hat, vielleicht liegt es daran.
    Wären ein paar von euch so freundlich und würden mein Programm einfach mal eine Minute laufen lassen und mir sagen, ob es abgestürzt ist?

    Ich gib auch gleich mal den Quellcode mit. Man kann nichts besonderes machen, soll ja hauptsache nicht abstürzen.
    Ich programmiere mit Dev c++ weil mir zurzeit VC zerschossen ist. Ich kann kein neues Projekt mehr machen (ja ich weiß, dass es nicht mehr weiterentwickelt wird).

    http://rapidshare.com/files/392925472/AOE_0.1.1.103.zip



  • Es gibt einige Gründe, warum globale Variablen gefährlich sein können.

    • Globale Variablen scheinen auf den ersten Blick einfach und bequem zu sein. Dieser Eindruck entsteht, weil man sich weniger Gedanken über ein objektorientiertes und modulares Design macht: Eine Entität ist überall bekannt, man muss sie nicht in Beziehungen mit anderen Entitäten setzen und verzichtet auf Gliederung. Kurzfristige Bequemlichkeit ist allerdings ein sehr schlechtes Argument. Semantisch gesehen gibt es zudem relativ wenige Objekte, die "einfach so da" sein müssen, ohne dass die Zugehörigkeit genauer spezifiziert werden könnte.
    • Genau diese bequeme Denkweise wird einem nämlich langfristig zum Verhängnis. Bei zunehmender Grösse des Programms wird die Komplexität immer unüberschaubarer. Anstatt dass man wenige, genau definierte Abhängigkeiten hat, sind lauter globale Variablen vorhanden, welche kreuz und quer referenziert werden. Auf diese Weise geraten die Zuständigkeiten der einzelnen Programmbestandteile ausser Kontrolle, Aufgabenbereiche werden unnötig ausgeweitet.
    • Abgesehen von der Übersichtlichkeit riskiert man damit viele Fehler. Durch die grosse Schnittstelle kann man Zugriff kaum beschränken oder kontrollieren. Eine globale Variable kann von überall her verändert werden – diese Änderungen zurückzuverfolgen ist extrem mühsam bis unmöglich. Denn je lokaler ein Objekt gehalten wird und je weniger Zugriff es auf andere Objekte benötigt, desto weniger Seiteneffekte können auftreten und desto genauer kann die Semantik kontrolliert werden. Dies ist ein Grundprinzip der Kapselung. Ausserdem sind globale Objekte nicht gerade die beste Option, wenn es um Multithreading geht.
    • Wartung wird auch zum Problem. Während bei einem durchdachten Design mit sauber aufgetrennten Aufgabenbereichen minimale Codeänderungen für eine Änderung der Funktionalität benötigt werden, tendieren globale Variablen dazu, an sehr vielen verschiedenen Orten im Code verwendet zu werden. Diese müssen alle berücksichtigt werden, was Zeit und Aufwand bedeutet und ausserdem wiederum eine Fehlerquelle darstellt.
    • Mit vielen globalen Objekten steigen die Abhängigkeiten an die Typen. Bei der Verwendung müssen alle benötigten Headerdateien mit den Definitionen der Typen eingebunden werden. Je grösser ein Projekt wird und je mehr globale Variablen man besitzt, umso stärker steigt die Kompilierzeit. Ausserdem führt bereits die kleinste Änderung einer globalen Variable dazu, dass alle benutzenden Übersetzungseinheiten (das sind in der Regel viele) neu kompiliert werden müssen.

    Dennoch sollte man globale Variablen nicht grundsätzlich verteufeln. Gerade Variablen, die erst innerhalb von .cpp-Dateien deklariert werden, teilen viele der Probleme nicht. Besonders, wenn sie konstant sind. Dennoch sollte man Entscheidungen im Programmdesign generell sorgfältig treffen und auch an die Zukunft denken. In den meisten Fällen trifft es nun mal zu, dass eine globale Variable massiv mehr Nachteile ohne wirkliche Vorteile mit sich bringt. Und wenn man den Entwickler nach Argumenten fragt, ist selten von etwas anderem als Bequemlichkeit und Faulheit die Rede.

    Übrigens ist "global" im weiten Sinne zu verstehen. Öffentlich zugängliche statische Variablen und Methoden von Klassen sind nicht zwingend besser. Das trifft auch auf das Singleton-Pattern zu, welches höchstens einen Teil der erwähnten Probleme löst.



  • Samxxxx schrieb:

    Die Makros sind von Allegro. Ich glaube, die bringen einen kleinen geschwindigkeitsschub. Genau weiß ich das aber nicht. Steht halt so in der Dokumentation.

    Da steht sicher genauer, was die tun. Zumindest ist es unverantwortlich, diese zu verwenden, ohne ihre Bedeutung zu kennen. Wenn du sowas an vielen Orten tust, brauchst du dich über merkwürdiges Programmverhalten nicht zu wundern.



  • Nexus schrieb:

    Samxxxx schrieb:

    Die Makros sind von Allegro. Ich glaube, die bringen einen kleinen geschwindigkeitsschub. Genau weiß ich das aber nicht. Steht halt so in der Dokumentation.

    Da steht sicher genauer, was die tun. Zumindest ist es unverantwortlich, diese zu verwenden, ohne ihre Bedeutung zu kennen. Wenn du sowas an vielen Orten tust, brauchst du dich über merkwürdiges Programmverhalten nicht zu wundern.

    In der Dok steht, wie man eine konstante Framerate erzeugt. Ich hab das mal übernommen. Ehrlich gesagt ich hab ein Jahr lang nicht mehr mit Allegro4 programmiert, sondern mit Allegro 5.

    Zur der Dok:

    LOCK_VARIABLE - Locks the memory of a variable used by a timer.
    LOCK_FUNCTION - Locks the memory of a function used by a timer.
    END_OF_FUNCTION - Locks the code used by a timer.

    ->http://www.allegro.cc/manual/

    Das Merkwürdige Verhalten ist in Allegro4 nicht mehr da, aber ich traue meinem Programm nicht. Ich glaube da ist irgendwo ein fetter Speicherfehler der sich immer meldet, wenn er nicht gebraucht wird.



  • Auch der Headercocktail in deiner stdafx.h könnte die Ursache für solche Spässe sein.
    Also ich hab es nicht ganz durchgeprüft

    #include <malloc.h>
    

    in einem Projekt mit

    new
    

    und

    delete
    

    halte ich für keine gute Idee - auch, wenn man es immer wieder im Netz antrifft.

    Es gibt noch andere ähnliche Stellen in dem Projekt.



  • das heißt ich soll das rauswerfen. Aber viel tut viel, oder? Ich denke Schaden kann es nicht ein paar zu viele includes zu haben(denk ich mal). das malloc kam rein als ich mit der Zugriffsverletzung experimentierte (hab halt vergessen es wieder rauszuwerfen).



  • Ich hatte gehofft auf der Seite tut sich was oder ist die nur noch aus Tradition online:
    http://msdn.microsoft.com/en-us/library/kftdy56f(VS.71).aspx

    Mix aus C und C++ Headern 🙄 aber solange die C99 weitgehend ignorieren ...



  • Du solltest dich entscheiden ob du C oder C++ programmieren möchtest, je nachdem in welcher Reihenfolge du die Header einträgst, von denen es eine C und eine C++ Variante gibt, und in welcher Folge du dann Funktionen von denen nutzt kann es sein das du dir die falschen Kombinationen zusammenbaust. Also theoretisch kann es sein, das der Speicher nicht mehr sauber verwaltet wird, und es zu "seltsamen" Abstürzen kommt.

    Ist bei einem Compiler der C99 kaum umsetzt weniger ins Gewicht fallend.

    MfG f.-th.



  • wäre noch zu erwähnen, dass Allegro in C geschrieben ist, weswegen man zwangsläufig an manchen Stellen C-Header braucht. Wenn du unbeding C++ benutzten willst, kannst du auch nach einem Allegro-C++-Wrapper suchen. Vielleicht gibt's da etwas passendes.



  • Gerade, wenn umfangreiche Erweiterungen in C oder C++ zum Einsatz kommen sollen, kann ein sparsamer Einsatz der Header bei dem es auch noch auf die richtige Reihenfolge ankommen kann, einem Stress ersparen.

    Also bei Projekten mit Verschiedene Programmiersprachen, versuchen die möglichst sauber zu trennen und die erforderlichen Schnittstellen gut dokumentieren und nicht irgend wo verstecken, was ja bei C und C++ Projekten einfach möglich ist, aber oft eine Fehlerquelle darstellt.

    Hier mal auf die Schnelle ein Link, nicht getestet:
    http://www.proggen.org/doku.php?id=allegro:start

    Allegro.hpp <- ich hoffe mal, das die nicht nur den Header umbenannt haben.

    MfG f.-th.


Anmelden zum Antworten