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

Black-Panther

Alter Hase

  • »Black-Panther« ist der Autor dieses Themas

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

1

06.06.2007, 20:47

Fehler bei Freigabe von allokiertem Speicher in Liste

Hallo!

Ich bin gerade auf ein Problem gestoßen, dass mich total verwirrt! Also: Ich habe eine Template-Klasse (wenn Code gewünscht, kein Problem) welche eine Liste darstellt. Im Spiel selbst dann, hab ich zwei Listen verschiedenen Typs. m_pBuildings und m_pppDivisions (ist ein Array von Listen, doch der Einfachheit halber sagen wir, es handle sich um eine Liste). Am Ende des Programms durchlaufe ich mit einem Iterator (ebenfalls eine Template-Klasse) alle Objekte welche in der Liste sind, und lösche sie, um sie dann aus der Liste zu löschen (ich mache das BEWUSST so, weil ich so den Tod der Einheit bzw des Gebäudes "simuliere" [ich könnte ja auch, alle deinitialisieren und dann die gesamte Liste löschen!]). Wenn jetzt nur EINE Liste Einträge enthält, dann funktioniert das Programm wurderbar (ergo kein Fehler in der Listen- sowie Iterator-Klasse). Wenn aber BEIDE Listen mindestens EINEN Eintrag besitzen, so stürtzt das Programm beim "Remove" des LETZTEN Eintrags der ZWEITEN Liste ab. (Egal WELCHE Liste ich zuerst leere, es ist immer die 2.!)
Sobald das Programm abstürtzt, macht mir der Debugger die Datei free.c an der Stelle:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
#endif  /* CRTDLL */
        else    //  __active_heap == __SYSTEM_HEAP

#endif  /* _WIN64 */
        {
            retval = HeapFree(_crtheap, 0, pBlock);    //<=== AN DIESER STELLE!

            if (retval == 0)
            {
                errno = _get_errno_from_oserr(GetLastError());
            }
        }
}

#else  /* WINHEAP */

auf (nur ein Auszug davon!)

So wie ich das interpretiere heißt das soviel, als würde er versuchen schon freigegebenen Speicher freizugeben. Kann mich auch leicht irren, aber auf keinem Fall weiß ich was da los ist... ich bin schon seit Stunden daran den Fehler zu finden (auch schon Step-by-Step trapassing) aber ich find und find den Fehler nicht. Kein Null-Pointer, kein cdcdcdcd-Pointer NIX... Hoffe ihr könnt mir helfen.

PS: Wenn ihr Code braucht, sagt mir was ihr wollt! ;)
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

06.06.2007, 20:57

Re: Fehler bei Freigabe von allokiertem Speicher in Liste

Zitat von »"Black-Panther"«

PS: Wenn ihr Code braucht, sagt mir was ihr wollt! ;)

Ein möglichst kurzes(!) Beispiel, welches das Verhalten demonstriert.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

3

06.06.2007, 21:00

Zeig mal deine Löschen Sache(also Code mit den Remove Krams).
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

Black-Panther

Alter Hase

  • »Black-Panther« ist der Autor dieses Themas

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

4

06.06.2007, 22:12

Ok... versuchs kurz zu halten...

Also, das ist die Stelle wo ich mit dem Iterator die Liste durchlaufe:

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
//Alle Einheiten löschen

    CGame* pGame = CMain::Instance().GetCurrentGameState<CGame>();
    for(UINT y = 0; y < pGame->m_iGridHeight; ++y)
    {
        for(UINT x = 0; x < pGame->m_iGridWidth; ++x)
        {
            for(ogUtilsIterator<CDivision*> i = m_pppDivisions[y][x].Begin(); i.NotEndOfList(); ++i)
            {
                //Einheit dieses Sektors löschen

                og2DVector vPos = og2DVector(static_cast<float>(x), static_cast<float>(y));
                ogEMS::Instance().SendOneMessage(this, OTCEM_DIVISIONDESTROYED, &i, &vPos);
            }
        }
        OG_SAFE_DELETE_ARRAY(m_pppDivisions[y]);
    }
    OG_SAFE_DELETE_ARRAY(m_pppDivisions);

    //Alle Buildings löschen

    for(ogUtilsIterator<CBuilding*> iterator = m_pBuildings.Begin(); iterator.NotEndOfList(); ++iterator)
    {
        ogEMS::Instance().SendOneMessage(this, OTCEM_BUILDINGDESTROYED, &iterator);
    }

Wie gesagt... die Reihenfolge ist egal, der Fehler tritt immer beim Löschen des letzten Eintrags der 2. Liste auf (2. Liste, weil bei den GRID-Listen nur eine Einträge enthält!)

Das MessageSystem ruft diese zwei Exit-Funktionen auf:

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
bool BuildingDestroyed(ogUtilsIterator<CBuilding*>* iterator)
    {
        //Aus EntityManager löschen

        ogEMS::Instance().DeleteObject(**iterator);

        //Instanz selbst löschen

        OG_SAFE_DELETE(iterator->m_pCurrent->Data);

        //Aus GebäudeListe entfernen

        m_pBuildings.Remove(iterator);
        return true;
    }

    bool DivisionDestroyed(ogUtilsIterator<CDivision*>* it, const UINT x, const UINT y)
    {
        //Aus EntityManager löschen

        ogEMS::Instance().DeleteObject(**it);

        //Instanz selbst löschen

        OG_SAFE_DELETE(it->m_pCurrent->Data);
        
        //Aus der "richtigen" Liste löschen

        m_pppDivisions[y][x].Remove(it);
        return true;
    }

Beim Aufruf vom Letzten m_pBuildings.Remove(iterator); oder m_pppDivisions[y][x].Remove(it); hängt es sich auf.

Und hier noch die Remove-Funktion der Liste:

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
bool Remove(ogUtilsIterator<T>* it)
    {
        ogUtilsListEntry<T>* pTemp = m_pFirst;
        ogUtilsListEntry<T>* pLast = NULL;
        for(UINT i = 0; i < m_iSize; ++i)
        {
            if(it->m_pCurrent == pTemp)
            {
                if(pLast) pLast->pNext = pTemp->pNext;
                else m_pFirst = pTemp->pNext;
                if(pTemp == m_pLast) m_pLast = pLast;

                it->m_pNextOne = pTemp->pNext;
                it->m_pCurrent = NULL;

                //Delete it!

                OG_SAFE_DELETE(pTemp);
                --m_iSize;
                return true;
            }
            pLast = pTemp;
            pTemp = pTemp->pNext;
        }
        return false;
    }

Und genau HIER = OG_SAFE_DELETE(pTemp); passiert es!!

Hoffe ihr habt jetzt eine Idee... Ich bin verzweifelt!
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

5

07.06.2007, 01:59

Viel interessanter wäre der Quellcode des Klassentemplates.

P.S.: Wann kapiert ihr endlich das man einen Zeiger vor dem Löschen NICHT auf 0 testen muss... Das ist sicher, der Standard garatiert es! :roll:
@D13_Dreinig

Black-Panther

Alter Hase

  • »Black-Panther« ist der Autor dieses Themas

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

6

07.06.2007, 13:41

Ok... Hier die Iterator Klasse und die Listen-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
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
template <typename T> class ogUtilsIterator;

template <typename T> struct ogUtilsListEntry
{
    ogUtilsListEntry<T>*        pNext;
    T                           Data;
};

template <typename T>
class ogUtilsList
{   
private:
    ogUtilsListEntry<T>*        m_pFirst;
    ogUtilsListEntry<T>*        m_pLast;
    UINT                        m_iSize;

public:
    ogUtilsList() : m_iSize(0), m_pFirst(NULL), m_pLast(NULL)       {}
    ~ogUtilsList()                                                  {Clear();}

    ogUtilsListEntry<T>*        Begin()             {return m_pFirst;}
    ogUtilsListEntry<T>*        End()               {return m_pLast;}
    UINT                        GetSize()           {return m_iSize;}
    //-------------------------------------------------------------------------//


    bool Insert(T& Data)
    {
        if(m_iSize <= 0) m_pFirst = m_pLast = new ogUtilsListEntry<T>;
        else
        {
            m_pLast->pNext  = new ogUtilsListEntry<T>;
            m_pLast         = m_pLast->pNext;
        }
        m_pLast->pNext = NULL;
        m_pLast->Data  = Data;
        ++m_iSize;
        return true;
    }

    bool Remove(T& Data)
    {
        ogUtilsListEntry<T>* pTemp = m_pFirst;
        ogUtilsListEntry<T>* pLast = NULL;
        for(UINT i = 0; i < m_iSize; ++i)
        {
            if(::memcmp(&(pTemp->Data), &Data, sizeof(T)) == 0)
            {
                if(pLast) pLast->pNext = pTemp->pNext;
                else m_pFirst = pTemp->pNext;
                if(pTemp == m_pLast) m_pLast = pLast;

                //Delete it!

                OG_SAFE_DELETE(pTemp);
                --m_iSize;
                return true;
            }
            pLast = pTemp;
            pTemp = pTemp->pNext;
        }
        return false;
    }
    bool Remove(ogUtilsIterator<T>* it)
    {
        ogUtilsListEntry<T>* pTemp = m_pFirst;
        ogUtilsListEntry<T>* pLast = NULL;
        for(UINT i = 0; i < m_iSize; ++i)
        {
            if(it->m_pCurrent == pTemp)
            {
                if(pLast) pLast->pNext = pTemp->pNext;
                else m_pFirst = pTemp->pNext;
                if(pTemp == m_pLast) m_pLast = pLast;

                it->m_pNextOne = pTemp->pNext;
                it->m_pCurrent = NULL;

                //Delete it!

                OG_SAFE_DELETE(pTemp);
                --m_iSize;
                return true;
            }
            pLast = pTemp;
            pTemp = pTemp->pNext;
        }
        return false;
    }

    bool Clear()
    {
        for(UINT i = 0; i < m_iSize; ++i)
        {
            ogUtilsListEntry<T>* pTemp = m_pFirst;
            m_pFirst = m_pFirst->pNext;
            OG_SAFE_DELETE(pTemp);
        }
        m_iSize     = 0;
        m_pFirst    = NULL;
        m_pLast     = NULL;
        return true;
    }
};

template <typename T>
class ogUtilsIterator
{
public:
    ogUtilsListEntry<T>*        m_pCurrent;
    //Wird verwendet, um während eines Schleifendurchgangs auch etwas aus der Liste löschen zu können

    //Hier wird dann gespeichert, auf welchen Eintrag der Iterator beim nächsten ++ springen soll

    ogUtilsListEntry<T>*        m_pNextOne;

    ogUtilsIterator() : m_pCurrent(NULL)                                    {}
    ogUtilsIterator(ogUtilsListEntry<T>* pStart) : m_pCurrent(pStart)       {}
    ~ogUtilsIterator()                                                      {}

    bool                    EndOfList()                 {return m_pCurrent == NULL;}
    bool                    NotEndOfList()              {return m_pCurrent != NULL;}
    void                    SetData(T NewData)          {if(m_pCurrent) m_pCurrent->Data = NewData;}

    //Operatoren

    ogUtilsIterator<T>& operator ++ ()                              
        {if(m_pCurrent) m_pCurrent = m_pCurrent->pNext; else {m_pCurrent = m_pNextOne; m_pNextOne = NULL;} return *this;}
    ogUtilsIterator<T>& operator ++ (int)                           
        {ogUtilsIterator<T> OldIt = *this; if(m_pCurrent) m_pCurrent = m_pCurrent->pNext; else {m_pCurrent = m_pNextOne; m_pNextOne = NULL;} return OldIt;}

    ogUtilsIterator<T>& operator () (ogUtilsListEntry<T>* pStart)   {m_pCurrent = pStart; return *this;}
    ogUtilsIterator<T>& operator = (ogUtilsListEntry<T>* pStart)    {m_pCurrent = pStart; return *this;}

    bool operator == (const ogUtilsListEntry<T>* pEntry) {return m_pCurrent == pEntry;}
    bool operator != (const ogUtilsListEntry<T>* pEntry) {return m_pCurrent != pEntry;}

    T* operator -> () {return &(m_pCurrent->Data);}
    T operator * () {return m_pCurrent->Data;}
};


PS: Wie meinst du? Was passiert denn, wenn ich einen delete mit einem NULL-Pointer mach?
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

Progater

Treue Seele

Beiträge: 119

Wohnort: BW

  • Private Nachricht senden

7

07.06.2007, 14:09

Zitat von »"David_pb"«

P.S.: Wann kapiert ihr endlich das man einen Zeiger vor dem Löschen NICHT auf 0 testen muss... Das ist sicher, der Standard garatiert es! Rolling Eyes

Aus eigener Erfahrung kann ich mit Sicherheit sagen, dass Einige nicht mal das lesen, wo man sie ausdrücklich um Hilfe bittet.
Also nicht gleich hysterisch werden. ;)
To go back to the drawing board is not everyone's cup of tea! :-)

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

8

07.06.2007, 14:11

Evtl liegt es am Kopierverhalten deiner Liste Black-Panther. Falls du die mal kopieren solltest machst du nur Flache kopien.

Zum Null-Pointer. Da passiert garnix wenn du den löschst. Der Standard garantiert, dass das löschen eines Null-Zeigers sicher ist.

C-/C++-Quelltext

1
2
3
int* ptr = 0;
delete ptr; // nix passiert

delete 0; // genau das gleiche, nix passiert
@D13_Dreinig

Black-Panther

Alter Hase

  • »Black-Panther« ist der Autor dieses Themas

Beiträge: 1 443

Wohnort: Innsbruck

  • Private Nachricht senden

9

07.06.2007, 14:18

Hmmm... Also theoretisch kopier ich die Liste nicht... Sie ist einfach eine normale private Eigenschaft der CPlayer-Klasse...
Wie könnt ich denn testen, ob sie kopiert wird (Kopierkonstruktor?). Oder was soll ich probieren?
Soll ich die Instanz der Liste ebenfalls dynamisch allokieren?
stillalive studios
Drone Swarm (32.000 Dronen gleichzeitig steuern!)
facebook, twitter

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

10

07.06.2007, 14:19

Was du auf jedenfall machen solltest ist ein Kopierkonstruktor zu implementieren da eine Flache kopie der Liste ja nicht vorgesehen ist, oder? Da kannst du auch direkt im copy c'tor testen ob du mal ne Kopie der Liste anlegst oder nicht.
@D13_Dreinig

Werbeanzeige