Plötzliche Heap Exceptions



  • Hallo,

    ich bin immer noch relativ am Anfang von c++ und bin derzeit dabei, ein kleines Spiel zu programmieren (theoretisch soll es ein RPG werden, wobei ich vermutlich nicht das durchhaltevermögen und wissen habe, das Projekt zu vollenden).

    Wie auch immer, als ich heute an dem Projekt weitergearbeitet habe, und compilen wollte, habe ich direkt beim starten des Spiels Heap Exceptions bekommen.
    Unhandled exception at 0x7769E753 (ntdll.dll) in Survive.exe: 0xC0000374: Ein Heap wurde beschädigt (parameters: 0x776D4270).

    Ich bin komplett verwirrt. Ich kann mir nicht erklären, warum die Exception plötzlich auftaucht, und vorher verborgen war / nicht ausgelöst wurde. Der neu geschriebene Code kann eigentlich nichts daran verursacht haben (Alles hat geklappt, dann habe ich einen Teil wieder gelöscht - plötzlich funktioniert nichts mehr).

    Habe leider durch Google-Suchen keine Lösung gefunden. Soweit ich es verstanden habe, ist eine Heap-Exception oft ausgelöst durch das freigeben von Objekten, ohne das diese richtig erstellt wurden (o.Ä.).
    Ich finde allerdings keinen Pointer in meinem Code, der den Fehler auslöst 😞

    Ich kann leider keine Codeauszüge liefern, da ich keine Ahnung habe, wodurch der Fehler entsteht. Debuggen hat mir noch nicht weitergeholen, wobei ich darin auch kein Experte bin.
    Alles was ich tuen kann, ist euch das komplette Projekt geben. Die tinyxml-Klasse habe ich nicht selbst geschrieben, den Rest schon. Ich benutzte SFML.

    Ich würde mich sehr freuen, wenn mir jemand weiterhelfen kann. Ich schließe nicht aus, das es ein simpler Fehler ist, da ich noch Anfänger bin. Ich komme aber leider überhaupt nicht mehr weiter 😞

    Kann man in diesem Forum keine Anhänge erstellen? Ich finde keine Möglichkeit, deswegen ist hier der Downloadlink über Mediafire: http://www.mediafire.com/download/reewtk5tnmavalr/Survive.zip

    Freundliche Grüße,
    Smofe



  • Hey, ist leider viel Code... hast du evtl. noch weiter Ausgaben bevor
    dir das Ding um die Ohren fliegt?

    Was mir jetzt so beim überfliegen aufgefallen ist, das du glaub den falschen
    Map Konstruktor aufrufst.

    Versuch es mal mit

    Game::Game()
    {
    	window.create(sf::VideoMode(1280, 720), "Dungeon Survival Alpha v.0.1");
    	map = new Map;
    }
    


  • Zwei Punkte hierzu:

    1.: Du hast ein Problem mit deinem Code und stellst dazu eine Frage. Ok. Aber dazu kannst du (warum auch immer) keinen Code posten und gibst einfach das ganze Projekt an. Wenn sich tatsaechlich jemand da einliest, wird er folgendes tun: den Code soweit reduzieren, dass der Fehler gerade noch/nicht mehr auftritt. Wenn der Code nur noch das NOETIGSTE enthaelt, den Fehler zu reproduzieren, wird nicht mehr viel uebrig sein. Dann kann man auch leicht sagen, was du falsch machst.
    Genau das solltest du auch tun. Das ist sehr wertvoll, du nimmst deinen eigenen Code auseinander, lernst etwas dabei und findest den Fehler. Wenn du ihn dann nicht verstehst, kannst du das "minimale kompilierbare Beispiel" (sehr wichtig) hier posten und nachfragen.

    2.: Selbst wenn sich jemand in deinen Code einlesen wollte: die .zip-Datei ist 17 MB (!) gross. Was zur hoelle ist da drin? Hier kann man auch reduzieren.

    Es ist ok, als Anfaenger nicht genau zu wissen, wie man Fehler finden kann. Auch debuggen will gelernt sein. Es ist aber nicht ok, den kompletten Code zu liefern und zu sagen, naja, keine Ahnung wo der Fehler auftritt, schaut doch mal rein.
    Du hast deine Frage heoflich gestellt und ich schreibe hier zugegebenermassen etwas flapsig. Nimm das nicht persoenlich, wir helfen gerne aber dazu braucht es etwas Eigeninitiative seitens des Fragestellers.



  • Zwei Punkte hierzu:

    1.: Du hast ein Problem mit deinem Code und stellst dazu eine Frage. Ok. Aber dazu kannst du (warum auch immer) keinen Code posten und gibst einfach das ganze Projekt an. Wenn sich tatsaechlich jemand da einliest, wird er folgendes tun: den Code soweit reduzieren, dass der Fehler gerade noch/nicht mehr auftritt. Wenn der Code nur noch das NOETIGSTE enthaelt, den Fehler zu reproduzieren, wird nicht mehr viel uebrig sein. Dann kann man auch leicht sagen, was du falsch machst.
    Genau das solltest du auch tun. Das ist sehr wertvoll, du nimmst deinen eigenen Code auseinander, lernst etwas dabei und findest den Fehler. Wenn du ihn dann nicht verstehst, kannst du das "minimale kompilierbare Beispiel" (sehr wichtig) hier posten und nachfragen.

    2.: Selbst wenn sich jemand in deinen Code einlesen wollte: die .zip-Datei ist 17 MB (!) gross. Was zur hoelle ist da drin? Hier kann man auch reduzieren.

    Es ist ok, als Anfaenger nicht genau zu wissen, wie man Fehler finden kann. Auch debuggen will gelernt sein. Es ist aber nicht ok, den kompletten Code zu liefern und zu sagen, naja, keine Ahnung wo der Fehler auftritt, schaut doch mal rein.
    Du hast deine Frage heoflich gestellt und ich schreibe hier zugegebenermassen etwas flapsig. Nimm das nicht persoenlich, wir helfen gerne aber dazu braucht es etwas Eigeninitiative seitens des Fragestellers.



  • Erstmal vielen Dank für die schnellen Antworten!

    NeulingX schrieb:

    Game::Game()
    {
    	window.create(sf::VideoMode(1280, 720), "Dungeon Survival Alpha v.0.1");
    	map = new Map;
    }
    

    Ist das ein Unterschied?

    Game::Game()
    {
    	window.create(sf::VideoMode(1280, 720), "Dungeon Survival Alpha v.0.1");
    	map = new Map();
    }
    

    Hyde++ schrieb:

    Zwei Punkte hierzu:

    1.: Du hast ein Problem mit deinem Code und stellst dazu eine Frage. Ok. Aber dazu kannst du (warum auch immer) keinen Code posten und gibst einfach das ganze Projekt an. Wenn sich tatsaechlich jemand da einliest, wird er folgendes tun: den Code soweit reduzieren, dass der Fehler gerade noch/nicht mehr auftritt. Wenn der Code nur noch das NOETIGSTE enthaelt, den Fehler zu reproduzieren, wird nicht mehr viel uebrig sein. Dann kann man auch leicht sagen, was du falsch machst.
    Genau das solltest du auch tun. Das ist sehr wertvoll, du nimmst deinen eigenen Code auseinander, lernst etwas dabei und findest den Fehler. Wenn du ihn dann nicht verstehst, kannst du das "minimale kompilierbare Beispiel" (sehr wichtig) hier posten und nachfragen.

    2.: Selbst wenn sich jemand in deinen Code einlesen wollte: die .zip-Datei ist 17 MB (!) gross. Was zur hoelle ist da drin? Hier kann man auch reduzieren.

    Es ist ok, als Anfaenger nicht genau zu wissen, wie man Fehler finden kann. Auch debuggen will gelernt sein. Es ist aber nicht ok, den kompletten Code zu liefern und zu sagen, naja, keine Ahnung wo der Fehler auftritt, schaut doch mal rein.
    Du hast deine Frage heoflich gestellt und ich schreibe hier zugegebenermassen etwas flapsig. Nimm das nicht persoenlich, wir helfen gerne aber dazu braucht es etwas Eigeninitiative seitens des Fragestellers.

    Erstmal tut es mir Leid, wenn das ganze so rüberkommt, als ob ich mich nicht selbst mit dem Problem beschäftigen will. Das ist überhaupt nicht der Fall, ich habe mich bereits viele Stunden damit beschäftigt, konnte den Fehler aber aufgrund meines fehlenden Wissen nicht finden oder einkesseln.
    Die Größe der Datei hängt an den Texturen, aber du hast Recht, hier hätte ich vorher etwas aussortieren sollen.

    Könnt ihr mir den Grundsätzlich in so fern helfen, dass ihr mir nochmal erklärt wie allgemein Heap Exceptions entstehen? Ist mein Verständniss da richtig?



  • Zu Heap exceptions kann ich dir nichts sagen, da kenne ich mich nicht aus.
    (Edit: bei mir tritt der Fehler auch nicht auf.)

    Es faellt aber einiges auf, wenn man deinen Code ansieht. Bei mir kompiliert er beispielsweise nicht.
    Zum einen liegt das am Pfadtrennzeichen ('\' statt '/', ich arbeite mit Linux). Soweit ich weiss, kann man auch auf Windows / nutzen. Hier kann ich mich aber auch irren.
    Zum anderen nutzt du strcmp, bindest aber nicht <cstring> ein.

    Beim Kompilieren erhaelt man einen Haufen warnungen, du solltest immer die Warnungen einschalten und diese natuerlich auch nicht ignorieren:

    Animation.cpp:20:20: warning: comparison of integers of different signs: 'int' and 'size_type' (aka 'unsigned long') [-Wsign-compare]
            for (int i = 0; i < textures.size(); i++)
                            ~ ^ ~~~~~~~~~~~~~~~
    

    Ok, das kannst du erstmal ignorieren.

    In file included from Game.cpp:2:
    In file included from ./Map.h:7:
    ./Player.h:17:7: warning: 'Player::update' hides overloaded virtual function [-Woverloaded-virtual]
            void update(Game& game, float);
                 ^
    ./Character.h:16:15: note: hidden overloaded virtual function 'Character::update' declared here: different number of parameters (1 vs 2)
            virtual void update(Game& game);
                         ^
    

    Dies kannst du durch ein

    using Character::update;
    

    in der Definition von Player loesen, allerdings kommen noch weitere solche Warnung. Ich habe jetzt nicht viel gelesen, aber eventuell sollte Character::update noch einen weiteren Parameter spendiert bekommen. Die unterschiedliche Signatur (1 Parameter vs. 2 Parameter) ist naemlich die Ursache fuer diese Warnung.

    Map.cpp:252:44: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]
                                    xmlNode = searchXMLByProperty(xmlNode, "tile", "animation", true);
                                                                           ^
    

    searchXMLByProberty bekommt als zweiten Parameter einen char*, du uebergibst aber ein const char*. Ich weiss nicht, was in der Funktion passiert, aber es wirkt, als wuerde dieser Parameter geaendert. Sollte dies nicht der Fall sein, verstoesst der Autor der Funktion gegen etwas, was man 'const-correctness' nennt. Das bedeutet, dass Parameter, die nicht veraendert werden, auch als unveraenderlich markiert werden sollten. Das Problem: du darfst ein String-literal nicht aendern, daher sollte der typ auch immer const char* sein (Zeiger auf konstante Zeichen).
    -> Code angucken, falls der den String aendert musst du selbst Speicher hierfuer anfordern.

    Map.cpp:391:1: warning: control may reach end of non-void function [-Wreturn-type]
    }
    

    Nicht schoen. Es gibt also Faelle, in denen du irgendeinen Muell als Rueckgabewert erhaelst. Du solltest hier eine Fehlerbehandlung oder aehnliches einbauen.

    Fehler zu nicht-verwendeten Variablen lasse ich mal durchgehen, du bist ja noch in der Entwicklungsphase.

    Player.cpp:34:38: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]
                            case TOP: animation.playAnimation("walkcycle_up");
                                                              ^
    

    Oben besprochene Warnung, hier kannst du aber selbst etwas tun: mache den entsprechenden Parameter const oder besser: nimm std::string. Vergiss char*. Ueberall.

    Hier sind keine Warnungen, die deinen Fehler erklaeren, daher kann ich nur sagen: reduzieren und Fehler suchen.

    Zu Map:
    Warum als Pointer? Nimm doch einfach eine "normale" Instanz. Dann kannst du dir auch das (ironischerweise auskommentierte) delete map im Destruktor sparen.



  • Hyde++ schrieb:

    Zu Heap exceptions kann ich dir nichts sagen, da kenne ich mich nicht aus.
    (Edit: bei mir tritt der Fehler auch nicht auf.)

    Es faellt aber einiges auf, wenn man deinen Code ansieht. Bei mir kompiliert er beispielsweise nicht.
    Zum einen liegt das am Pfadtrennzeichen ('\' statt '/', ich arbeite mit Linux). Soweit ich weiss, kann man auch auf Windows / nutzen. Hier kann ich mich aber auch irren.
    Zum anderen nutzt du strcmp, bindest aber nicht <cstring> ein.

    Beim Kompilieren erhaelt man einen Haufen warnungen, du solltest immer die Warnungen einschalten und diese natuerlich auch nicht ignorieren:

    Animation.cpp:20:20: warning: comparison of integers of different signs: 'int' and 'size_type' (aka 'unsigned long') [-Wsign-compare]
            for (int i = 0; i < textures.size(); i++)
                            ~ ^ ~~~~~~~~~~~~~~~
    

    Ok, das kannst du erstmal ignorieren.

    In file included from Game.cpp:2:
    In file included from ./Map.h:7:
    ./Player.h:17:7: warning: 'Player::update' hides overloaded virtual function [-Woverloaded-virtual]
            void update(Game& game, float);
                 ^
    ./Character.h:16:15: note: hidden overloaded virtual function 'Character::update' declared here: different number of parameters (1 vs 2)
            virtual void update(Game& game);
                         ^
    

    Dies kannst du durch ein

    using Character::update;
    

    in der Definition von Player loesen, allerdings kommen noch weitere solche Warnung. Ich habe jetzt nicht viel gelesen, aber eventuell sollte Character::update noch einen weiteren Parameter spendiert bekommen. Die unterschiedliche Signatur (1 Parameter vs. 2 Parameter) ist naemlich die Ursache fuer diese Warnung.

    Map.cpp:252:44: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]
                                    xmlNode = searchXMLByProperty(xmlNode, "tile", "animation", true);
                                                                           ^
    

    searchXMLByProberty bekommt als zweiten Parameter einen char*, du uebergibst aber ein const char*. Ich weiss nicht, was in der Funktion passiert, aber es wirkt, als wuerde dieser Parameter geaendert. Sollte dies nicht der Fall sein, verstoesst der Autor der Funktion gegen etwas, was man 'const-correctness' nennt. Das bedeutet, dass Parameter, die nicht veraendert werden, auch als unveraenderlich markiert werden sollten. Das Problem: du darfst ein String-literal nicht aendern, daher sollte der typ auch immer const char* sein (Zeiger auf konstante Zeichen).
    -> Code angucken, falls der den String aendert musst du selbst Speicher hierfuer anfordern.

    Map.cpp:391:1: warning: control may reach end of non-void function [-Wreturn-type]
    }
    

    Nicht schoen. Es gibt also Faelle, in denen du irgendeinen Muell als Rueckgabewert erhaelst. Du solltest hier eine Fehlerbehandlung oder aehnliches einbauen.

    Fehler zu nicht-verwendeten Variablen lasse ich mal durchgehen, du bist ja noch in der Entwicklungsphase.

    Player.cpp:34:38: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]
                            case TOP: animation.playAnimation("walkcycle_up");
                                                              ^
    

    Oben besprochene Warnung, hier kannst du aber selbst etwas tun: mache den entsprechenden Parameter const oder besser: nimm std::string. Vergiss char*. Ueberall.

    Hier sind keine Warnungen, die deinen Fehler erklaeren, daher kann ich nur sagen: reduzieren und Fehler suchen.

    Zu Map:
    Warum als Pointer? Nimm doch einfach eine "normale" Instanz. Dann kannst du dir auch das (ironischerweise auskommentierte) delete map im Destruktor sparen.

    Vielen Dank für die Hilfe! Tatsächlich lag es an den fehlenden Return-Fällen. 🙄 Ob das den Fehler verursacht oder nur offenbart hat, kann ich derzeit noch nicht sagen; das Programm läuft allerdings wieder!
    Die anderen von dir gennanten Dinge werde ich verbessern! 🙂

    Puh, ich bin froh, der Fehler hat mich zum Verzweifeln gebracht 🕶



  • Hm, fuege doch mal eine Ausgabe im nicht behandelten return-Zweig ein. Dann muesstest du ja sehen, ob dieser Fall auftritt und ob hier (wenn du den alten code verwendest) dein Fehler auftritt.



  • Hyde++ schrieb:

    2.: Selbst wenn sich jemand in deinen Code einlesen wollte: die .zip-Datei ist 17 MB (!) gross. Was zur hoelle ist da drin? Hier kann man auch reduzieren.

    Visual Studio erzeugt für sein Intellisense eine "kleine" Datenbankdatei, die *.sdf Datei, bzw im laufenden Betrieb *.opensdf. Die sind so riesig. Von etwa 40 MB ungepackt sind 37MB für die *.sdf.



  • Und die restlichen 3 MB gehen vermutlich für .obj und .pdb Files drauf.


Anmelden zum Antworten