Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

10.04.2016, 03:33

C++ | SFML | Probleme mit dem Heap?

Hallo liebe Community,
nach langer Abstinenz habe ich mich wieder an einem kleinen Spiel versucht (Monty-Hall-Problem) Bisher ist das meiste gut gelaufen, nun ist aber ein Fehler aufgetreten, den ich mir absolut nicht erklären kann:

Spieldesign:
In dem Spiel gibt es mehrere "gameStates" - Intro, Menu, Spiel, Auswertung - alles ein unique_ptr der je nach Spielstatus angepasst wird.

Im Spielmodus konnte ich bisher gut programmieren und habe auch dort das eigentliche Spiel fertig. Nun möchte ich eine kleine Statistik anlegen und auswerten, dazu wird der gameState wieder gewechselt.

Fehlerbeschreibung:
Nun habe ich ein paar Dinge bei der Auswertung programmiert - im Prinzip werden die gleichen Algorithmen verwendet, wie in der Spiel Bereich. Allerdings setzt der Compiler mir einen Breackpoint, den ich mir nicht erklären kann, kurz nachdem der Spielstatus gewechselt wurde. Wenn ich auf Continue gehe, läuft das Spiel normal weiter. Und alles wird sauber angezeigt.

Fehlercode:
Der Output sagt an dieser Stelle folgendes:
HEAP: Free Heap block 0744C860 modified at 0744CBD4 after it was freed
ziegenproblem.exe has triggered a breakpoint.

Mein Problem ist nun, dass ich nicht weiß wonach ich genau suchen soll, bzw. wie ich den Fehler finden soll. Ich habe deshalb auch erst einmal davon abgesehn Code zu posten, da ich noch nicht genau eingrenzen kann, wo der Fehler liegt und ich euch nicht den kompletten Quellcode zumuten möchte. Ich nutze SFML.

Danke schon mal für die Hilfe und die Hinweise.
VG

2

10.04.2016, 07:07

Und welche Zeile Code steht an der Stelle wo der Fehler geworfen wird?
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

3

10.04.2016, 15:20

Beim Rumprobieren habe ich gerade gemerkt, dass die gesamte Klasse wohl verbugt ist, aber eins nach dem anderen:

Breackpoint taucht auf bei window.display():

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
while (window.isOpen())
{
    CurrentState->HandleEvents(*this);

    window.clear();

    CurrentState->Update(*this);
    CurrentState->Draw(*this);

    window.display();
}


Hier die zugehörige Draw Methode:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
void Statsstate::Draw(Game& game)
{
    game.window.draw(sBackground);
    /*game.window.draw(shSwapLoose);
    game.window.draw(shNoSwapWin);
    game.window.draw(shNoSwapLoose);
    game.window.draw(shSwapWin);*/
}


Wenn ich die anderen Sachen entkommentiere, wird der Breackpoint bei shSwapLoose gesetzt. sBackground ist vom typ ein sf::Sprite, und shSwapLoose vom Typ ein sf::Shape.
Initialisierung erfolgt im Konstruktor der Klasse:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (!tBackground.loadFromFile("pics\\Texturen\\stats.png"))
    {
        std::cout << "Textur konnte nicht geladen werden!" << std::endl;
    }
tBackground.setSmooth(true);
sBackground.setTexture(tBackground);

[...]

shSwapWin.setFillColor(sf::Color(0.f, 170.f, 130.f));
if (swapWin + swapLoose != 0)
    {
        shSwapWin.setSize(sf::Vector2f(100.f, (static_cast<float> (swapWin) / (swapWin + swapLoose)) * 289));
    }
    else if (swapWin + swapLoose == 0)
    {
        shSwapWin.setSize(sf::Vector2f(100.f, 0));
    }   
shSwapWin.setOrigin(0, shSwapWin.getGlobalBounds().height);
shSwapWin.setPosition(203.f,661.f);


Die Integer Variablen swapWin; swapLoose ... werden bei der Erzeugung der Klasse übergeben.

Beim rumprobieren habe ich gemerkt, dass auch die Events nicht ordentlich abgefragt werden. Da zuckt sich nichts, weder bei einem Mausklick noch beim Drücken der Esc taste. Setzte ich den VideoMode auf Fullscreen hängt der sich ganz auf. Vom Prinzip her habe ich die Klasse wie die Spielklasse programmiert - und die läuft.

Vielen Dank für eure Zeit!
VG

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

10.04.2016, 15:46

Die Fehlermeldung ist eigentlich recht eindeutig. Du greifst irgendwo auf Speicher zu, der schon freigegeben wurde. Also läuft irgendwo ein Zombie-Pointer oder eine Zombie-Referenz auf etwas herum, was eigentlich schon gestorben ist. Oft werden solche Fehler nicht dort angezeigt, wo sie verursacht werden. Soll heißen, dass der "this" Pointer oftmals schon ungültig ist und das daher nur innerhalb von Methoden auftaucht. Die Ursache liegt aber ganz woanders, nämlich dort, wo das aufgerufene Objekt referenziert wird.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

5

10.04.2016, 16:28

Wie sieht die Statsstate Klasse aus?

Die Draw-Methode finde ich etwas komisch.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

6

10.04.2016, 16:37

Hab Dank,
ich habe die Fehlerart verstanden. Dummerweise habe ich keine Ahnung wie ich diesen Zeiger finden kann, wenn sie nicht da angezeigt werden, wo sie verursacht werden.

Das Problem scheint dann ja aber in der erzeugung der neuen Klasse zu liegen. Deshalb hier noch einmal etwas Code - Wäre super, wenn ihr noch mal drüber schauen könntet.

Game Verwaltung:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# include "game.h"

Game::Game()
{
    window.create(sf::VideoMode(1600, 900), "Let's make a Deal!"/*, sf::Style::Fullscreen*/);
    
    running = true;
}


void Game::Run()
{
    while (window.isOpen())
    {
        CurrentState->HandleEvents(*this);

        window.clear();

        CurrentState->Update(*this);
        CurrentState->Draw(*this);

        window.display();
    }
}

bool Game::isRunning()
{
    return running;
}

void Game::ChangeState(gameStates newState)
{
    switch (newState)
    {
        case gameStates::INTRO:
            CurrentState = std::move(std::unique_ptr<Introstate>(new Introstate));
        break;

        case gameStates::MAINMENU:
            CurrentState = std::move(std::unique_ptr<MainMenuState>(new MainMenuState));
        break;
    }
}

void Game::ChangeState(gameStates newState, int sWin, int sLoose, int nSWin, int nSLoose)
{
    int tmpSWin = sWin;
    int tmpSLoose = sLoose;
    int tmpNSWin = nSWin;
    int tmpNSLoose = nSLoose;

    if (newState == gameStates::PLAY)
    {
        CurrentState = std::move(std::unique_ptr<Playstate>(new Playstate(tmpSWin, tmpSLoose, tmpNSWin, tmpNSLoose)));
    }
    else if (newState == gameStates::STATS)
    {
        CurrentState = std::move(std::unique_ptr<Statsstate>(new Statsstate(tmpSWin, tmpSLoose, tmpNSWin, tmpNSLoose)));
    }
    
}


Meine Vermutung liegt darin, dass bei der ChangeState Methode irgendwo ein Fehler liegt, den ich durch den Zusammenbau nicht sehe.


Und hier der Code, wie der Statistik Screen Aufgerufen wird:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void Playstate::HandleEvents(Game& game)
{
    sf::Event event;

    while (game.window.pollEvent(event))
    {
        if (event.type == sf::Event::Closed)
        {
            game.window.close();
            game.running = false;
        }

        if (event.type == sf::Event::MouseButtonReleased)
        {
            if (event.mouseButton.button == 0)
            {
                if (bStatsSelected)
                {
                    game.ChangeState(Game::gameStates::STATS, swapWin, swapLoose, noSwapWin, noSwapLoose);
                }
            }
        }
    }
}


Zur Vollständigkeit der Konstruktor der Statistik-Methode (der Rest scheint ja zu funktionieren)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Statsstate::Statsstate(int sWin, int sLoose, int nSWin, int nSLoose)
{

    swapWin = sWin;
    swapLoose = sLoose;
    noSwapWin = nSWin;
    noSwapLoose = nSLoose;

    if (!tBackground.loadFromFile("pics\\Texturen\\stats.png"))
    {
        std::cout << "Textur konnte nicht geladen werden!" << std::endl;
    }
    tBackground.setSmooth(true);
    sBackground.setTexture(tBackground);

    shSwapWin.setFillColor(sf::Color(0.f, 170.f, 130.f));
        if (swapWin + swapLoose != 0)
        {
            shSwapWin.setSize(sf::Vector2f(100.f, (static_cast<float> (swapWin) / (swapWin + swapLoose)) * 289));
        }
        else if (swapWin + swapLoose == 0)
        {
            shSwapWin.setSize(sf::Vector2f(100.f, 0));
        }   
    shSwapWin.setOrigin(0, shSwapWin.getGlobalBounds().height);
    shSwapWin.setPosition(203.f,661.f);

        [...]
}


VG

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

10.04.2016, 16:50

Durch Drüberfliegen habe ich erstmal nur den Hinweis, dass Du kein move brauchst, wenn Du eh per new ein neues Objekt für einen unique_ptr erzeugst.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

8

10.04.2016, 16:56

Mich hätte da interessiert wo in Statsstate window herkommt.

Dir ist bewusst das du bei jedem Wechsel den state neu erzeugst.
Sieht mir auch nach zyklischen Abhängigkeiten aus Game kennt State und State kennt Game.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

9

10.04.2016, 17:02

Die Statsstate Klasse:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifndef STATSSTATE_HPP
#define STATSSTATE_HPP

#include "game.h"
#include "Gamestate.h"

class Statsstate : public Gamestate
{
public:
    Statsstate(int sWin, int sLoose, int nSWin, int nSLoose);
    ~Statsstate();

    void HandleEvents(Game& game);     // Zum Beenden, zurückkehren in die Spielklasse
    void Update(Game& game);           // Abfrage, wo sich die Maus gerade befindet
    void Draw(Game& game);             // Zeichnen der einzelnen Objekte

private:
    bool bContinueSelected;
    bool bNewGameSelected;

    sf::Texture tBackground;
    sf::Sprite sBackground;

    int swapWin;
    [...] // weitere Variablen
};

#endif


Konstruktor und Draw Methode hatte ich ja schon gepostet. Kann auch zur vollständigkeit die anderen noch einmal Posten (Oder die .cpp datei komplett hochladen)

@BlueCobold - habe mir das System von Combobreacker (Youtube) abgeschaut und erweitert. Habe mich in unique_ptr noch nicht so tief eingearbeitet, dass ich es wagen könnte etwas zu verändern. - Das Spiel sollte möglichst schnell fertig werden, da ich es nächste Woche benötige (Langfristig kümmer ich mich natürlich darum). Ich habe das std::move() rausgenommen - Fehler ist immer noch da (alles andere funktioniert).

10

10.04.2016, 17:08

@ Koschi: Das window kommt von der Game Klasse (siehe unten) - Jep zyklische Abhängigkeiten - ist das das Problem?

C-/C++-Quelltext

1
2
3
4
5
6
Game::Game()
{
    window.create(sf::VideoMode(1600, 900), "Let's make a Deal!"/*, sf::Style::Fullscreen*/);
    
    running = true;
}

Werbeanzeige