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

13.11.2012, 18:21

C++ mit SFML: Fehlermeldung bei Schließen des Programms.

Hallo,
Ich schreibe zurzeit an einem Programm zur Darstellung von Wellen in C++ mit der Entwicklungsumgebung Visual C++ 2010 Express und der Bibliothek SFML, und habe dabei das Problem, dass ich, wenn ich das Fenster schließe, eine Fehlermeldung erhalte. Ich benutze dabei die Debug Version.
Die Fehlermeldung lautet folgendermaßen:

Debug Assertion Failed!
Program: <Verzeichnis und Dateiname des Programms>
File: f:\dd\vctools\crt_bld\self_x86\crt\src\dbgdel.cpp

EXPRESSION: _BLOCK_TYPE_IS_VALID (pHead->nBlockUse)

Habe schon bei Google nach diesem Problem gesucht, und gefunden, dass dieser Fehler wohl auftritt, wenn man versucht, Speicher freizugeben, der bereits freigegeben wurde.

Ich habe eine Klasse die heißt "Application", dort reserviere ich auch manuell Speicher. Und zwar definiere ich erst den Zeiger für die Welle mit dem new Operator, nachdem ich den Benutzer nach den Werten für die Welle gefragt habe, vorher ist er NULL. Jedoch gebe ich im Dekonstruktor der Klasse "Application" auch den Speicher wieder frei, und prüfe auch extra, ob der Zeiger nicht NULL ist.

Ich habe auch testweise die update- und render-Funktion der Application, welche bei jedem Durchgang der while-Schleife ausgeführt werden (die while-Schleife wird solange ausgeführt, wie das Fenster geöffnet ist) auskommentiert, dann gab es dasselbe Verhalten.
Wenn ich die "askForValues" Funktion des "application" Objekts auskommentiere, in der ganz am Anfang des Programms, vor der Erstellung des Fensters, die Werte für die Welle vom Benutzer in der Konsole abgefragt werden, stürzt das Programm nicht ab.
Wenn ich jedoch in der "askForValues" Funktion alles bis auf die Erstellung der Welle mit dem new-Operator auskommentiere, tritt der beschriebene Fehler auf. Also scheint es irgendein Problem mit der Speicherreservierung und Speicherfreigabe zu geben.

Anbei ist der Quelltext der für dieses Problem wichtigsten Funktionen:

main.cpp:

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
#include <SFML\Graphics.hpp>
#include "Application.hpp"
#include "Global.hpp"

int main ()
{
    Application application;
    bool timeRunning = false;

    application.askForValues ();
    
    sf::RenderWindow window (sf::VideoMode (SCREENWIDTH, SCREENHEIGHT, 32), "Wellen");

    sf::Clock clock;
    float time = 0.0f;
    float frametime = 0.0f;

    while (window.isOpen ())
    {
        sf::Event windowEvent;

        while (window.pollEvent (windowEvent))
        {
            if (windowEvent.type == sf::Event::Closed)
                window.close ();

            // wenn Leertaste gedrückt wird, Programm fortsetzen / pausieren
            else if (windowEvent.type == sf::Event::KeyPressed)
            {
                if (windowEvent.key.code == sf::Keyboard::Space)
                    timeRunning = !timeRunning;
            }
        }
        
        window.clear (sf::Color::White);

        frametime = clock.getElapsedTime().asSeconds();

        if (timeRunning)
            time += frametime;

        clock.restart ();

        application.update (time, frametime);
        application.render (&window);

        window.display ();
    }

    return 0;
}



askForValues Funktion der Application Klasse
(reduziert auf vorhandenes Problem, Rest wurde ja wie gesagt testweise auskommentiert und hat den Fehler nicht behoben):

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void Application::askForValues ()
{
    float amplitude = 1.0f, frequency = 1.0f, velocityOfPropagation = 1.0f;
    float xZoom = 250.0f, yZoom = 250.0f, timeZoom = 1.0f;
    int leftOffset = 100, bottomOffset = 100, rightOffset = 100, topOffset = 100;

    // Welle definieren
    m_pWave = new Wave (amplitude, frequency, velocityOfPropagation, 
                        xZoom, yZoom, timeZoom,
                        leftOffset, bottomOffset, rightOffset, topOffset);

    // Koordinatensystem definieren
    m_pCoordinateSystem = new CoordinateSystem (xZoom, yZoom, timeZoom, 
                                                leftOffset, bottomOffset, rightOffset, topOffset);
    m_pCoordinateSystem->create ();
}



Dekonstruktor der Application 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
Application::~Application ()
{
    // Speicher freigeben
    if (m_pWave != NULL)
    {
        delete (m_pWave);
        m_pWave = NULL;
    }
    
    // Text für FPS Anzeige, Typ: sf::Text*
    if (m_pFPSText != NULL)
    {
        delete (m_pFPSText);
        m_pFPSText = NULL;
    }

    if (m_pCoordinateSystem != NULL)
    {
        delete (m_pCoordinateSystem);
        m_pCoordinateSystem = NULL;
    }
}



In der Klasse CoordinateSystem wird auch Speicher auf dieselbe Methode reserviert und freigegeben, könnte das evtl. auch die Ursache sein?

Vielen Dank schonmal im voraus.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Jack069« (13.11.2012, 18:27)


eXpl0it3r

Treue Seele

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

2

13.11.2012, 23:59

Dein Code ist wahrscheinlich nicht direkt der Verursacher des Problems, obwohl manuelles Memory Management sehr wohl zu solchen Problemen führen kann. Das Applikationen in Verbindung mit SFML beim Verlassen crashen ist ein Phänomen, welches sich immer wieder zeigt und verschiedene Gründe haben kann.

Ich nehme jetzt einmal an, dass du SFML 2rc verwendest, ist das korrekt?
Dann die Frage, was genau definierst du im header 'Global.hpp', weil globale Instanzen (von SFML Klassen) mit einer sehr hohen wahrscheinlichkeit zu Problemen führen können.
Wenn du schreibst "das Fenster schliesse", dann meinst du wirklich das GUI Fenster oder? Weil wenn du das Konsolenfenster schliesst, dann ist das Verhalten undefiniert.
Wenn du sf::Text verwendest, solltest du zum einen die DefaultFont meiden und zum anderen im Konstruktor deine eigene Font laden. Die default Font ist ein bekannter Grund für solche Abstürzte und wurde u.a. deshalb in den neueren Versionen entfernt.

Ein gutes Verfahren Fehler zu finden ist, durch reduzieren des Codes. Nimm einfach immer mehr Codestücke weg, so dass es noch kompiliert und den Fehler reproduziert. Somit schränkst du die möglichen Fehlerquellen ein und es wird dir möglich den Fehler auf einen Bilck zu sehen und das kompakte Codestück einfach weiterzugeben, so dass andere daran arbeiten können.

Noch einen Tipp zum manuallen Memory Management (new/delete), such mal etwas im Internet über smart pointer, insbesondere std::unique_ptr und std::shared_ptr. ;)

Falls du aktuelle SFML Binaries willst, kannst du eins meiner Nightly Builds laden.
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

3

14.11.2012, 15:51

Dein Code ist wahrscheinlich nicht direkt der Verursacher des Problems, obwohl manuelles Memory Management sehr wohl zu solchen Problemen führen kann. Das Applikationen in Verbindung mit SFML beim Verlassen crashen ist ein Phänomen, welches sich immer wieder zeigt und verschiedene Gründe haben kann.

Ich nehme jetzt einmal an, dass du SFML 2rc verwendest, ist das korrekt?
Dann die Frage, was genau definierst du im header 'Global.hpp', weil globale Instanzen (von SFML Klassen) mit einer sehr hohen wahrscheinlichkeit zu Problemen führen können.
Wenn du schreibst "das Fenster schliesse", dann meinst du wirklich das GUI Fenster oder? Weil wenn du das Konsolenfenster schliesst, dann ist das Verhalten undefiniert.
Wenn du sf::Text verwendest, solltest du zum einen die DefaultFont meiden und zum anderen im Konstruktor deine eigene Font laden. Die default Font ist ein bekannter Grund für solche Abstürzte und wurde u.a. deshalb in den neueren Versionen entfernt.

Ein gutes Verfahren Fehler zu finden ist, durch reduzieren des Codes. Nimm einfach immer mehr Codestücke weg, so dass es noch kompiliert und den Fehler reproduziert. Somit schränkst du die möglichen Fehlerquellen ein und es wird dir möglich den Fehler auf einen Bilck zu sehen und das kompakte Codestück einfach weiterzugeben, so dass andere daran arbeiten können.

Noch einen Tipp zum manuallen Memory Management (new/delete), such mal etwas im Internet über smart pointer, insbesondere std::unique_ptr und std::shared_ptr. ;)

Falls du aktuelle SFML Binaries willst, kannst du eins meiner Nightly Builds laden.
Vielen Dank schonmal.
Ja, ich benutze die Version 2.0 RC. Und mit Fenster schließen meine ich auch das GUI Fenster, wenn ich das Konsolenfenster schließe, tritt dieser Fehler nicht auf.
Der Quelltext meiner "Global.hpp" Datei sieht folgendermaßen aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef GLOBAL_HPP
#define GLOBAL_HPP

#define PI 3.1415926f
#define SCREENWIDTH 1024
#define SCREENHEIGHT 768
#define LABEL_XDISTANCE 50
#define LABEL_YDISTANCE 50
#define LABEL_THICKNESS 2
#define LABEL_LENGTH 10

#endif


Instanzen von SFML Klassen werden dort nicht erstellt, lediglich die Bildschirmgröße, und ein paar Integer Konstanten, die ich zur Berechnung der Beschriftung des Koordinatensystems brauche.

Ich habe jetzt die Datei für die Schriftart Arial in den Debug-Ordner kopiert, im Quelltext eine sf::Font Instanz als Membervariable der jeweiligen Klasse erstellt, dann im KOnstruktor der jeweiligen Klasse die Schriftdatei geladen. Ich habe dann beim Initialisieren der sf::Text-Instanzen die Schrift direkt mit dem Konsturktor geladen, der Text wird auch fehlerlos dargestellt, jedoch stürzt das Programm immer noch ab wenn ich das GUI Fenster schließe.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Jack069« (14.11.2012, 16:23)


drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

4

14.11.2012, 16:04

Jedoch gebe ich im Dekonstruktor der Klasse "Application" auch den Speicher wieder frei, und prüfe auch extra, ob der Zeiger nicht NULL ist.

Habe mir jetzt nicht alles genau angeschaut, aber hier liegt üblicherweise der Anfängerfehler.

Du brauchst nicht zu überprüfen ob der Zeiger 0 ist oder nicht. delete auf einen 0-Zeiger ist kein Problem und macht einfach nichts.

Viel wichtiger ist, dass du alle Zeiger, wenn du ihnen keinen Speicher zuweisen kannst auf 0 initialisierst, was nämlich nicht standardmässig passiert. Wenn du das also nicht machst und du dem Zeiger keinen sinnvollen Wert zuweist, dann wirst du so einen Fehler, wie du ihn bekommen hast bekommen, wenn du delete darauf ausführst. In Code:

C-/C++-Quelltext

1
2
3
4
5
int* pn; // pn ist nicht 0!!

.... // nirgends wird pn Speicher zugewiesen

delete pn; // bum

vs.

C-/C++-Quelltext

1
2
3
4
5
int* pn = 0;

.... // nirgends wird pn Speicher zugewiesen

delete pn; // ok

5

14.11.2012, 16:43

Jedoch gebe ich im Dekonstruktor der Klasse "Application" auch den Speicher wieder frei, und prüfe auch extra, ob der Zeiger nicht NULL ist.

Habe mir jetzt nicht alles genau angeschaut, aber hier liegt üblicherweise der Anfängerfehler.

Du brauchst nicht zu überprüfen ob der Zeiger 0 ist oder nicht. delete auf einen 0-Zeiger ist kein Problem und macht einfach nichts.

Viel wichtiger ist, dass du alle Zeiger, wenn du ihnen keinen Speicher zuweisen kannst auf 0 initialisierst, was nämlich nicht standardmässig passiert. Wenn du das also nicht machst und du dem Zeiger keinen sinnvollen Wert zuweist, dann wirst du so einen Fehler, wie du ihn bekommen hast bekommen, wenn du delete darauf ausführst. In Code:

C-/C++-Quelltext

1
2
3
4
5
int* pn; // pn ist nicht 0!!

.... // nirgends wird pn Speicher zugewiesen

delete pn; // bum

vs.

C-/C++-Quelltext

1
2
3
4
5
int* pn = 0;

.... // nirgends wird pn Speicher zugewiesen

delete pn; // ok
Danke. Das hört sich echt logisch an, habe mir auch mal den Konstruktor der CoordinateSystem Klasse angeschaut, und habe gemerkt, dass ich die meisten zeiger gar nicht mit NULL initialisiert werden.

Ich habe jetzt alle Zeiger mit NULL initialisiert, und auch beim Freigeben des Speichers die Abfrage, ob der Zeiger != NULL ist entfernt, die braucht man ja nicht.
Zusätzlich habe ich auch noch den fehler gemacht, dass ich bei der Speicherreservierung für Arrays nur "delete (<variablenname>)" und nicht "delete [] (variablenname) " geschrieben hab.

Jetzt ist der Fehler endlich behoben, vielen Dank für die Hilfe!

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Jack069« (14.11.2012, 17:02)


Werbeanzeige