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

Gotbread

Alter Hase

  • »Gotbread« ist der Autor dieses Themas

Beiträge: 421

Beruf: Student (Etechnik) + Hiwi

  • Private Nachricht senden

1

15.10.2008, 17:52

Verkettete liste -> zugriffsfehler

Hallo liebe Community

ich habe ein problem mit einem speichermanager. weil ich viele kleine
speicherblöcke regelmäßig anfordere und freigebe, habe ich mir einen
eigenen geschrieben, der den speicher nicht sofort zurückgibt sondern
nur als frei markiert

das ganze wird in einem großen char* array mithilfe einer doppelt verketteten liste gespeichert:

Quellcode

1
2
3
4
5
6
/------------------------------------------------------\
|listinfo|USERDATA|       |listinfo|USERDATA|          |
\------------------------------------------------------/
^
|
mem


der speicherblock 'mem' enthält immer einige listendaten

C-/C++-Quelltext

1
2
3
4
5
struct node
{
    unsigned size;
    node *next, *last;
};

und direkt danach die benutzerdaten.

ein hilfszeiger 'p' zeigt immer auf den ersten knoten der in diesem
speicher liegt.

um einen bereich zu löschen hänge ich einfach die beiden zeiger um,
diese funktion sollte funktioniern

der code:

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
    void *alloc(unsigned size)
    {
        if (!mem)
            return 0;
        if (!p)
        // noch kein startknoten angelegt

        {
            if ((size + sizeof(node)) > memsize)
                return 0;

            p = reinterpret_cast<node *>(mem);  // knoten am begin des blocks erzeugen

            p->size = size;
            p->last = 0;
            p->next = 0;
            return p + 1;   // benutzerdaten stehen hinter den listeninformationen

        }
        else
        {
            if ((reinterpret_cast<char *>(p) - mem) >= (size + sizeof(node)))
            // wenn zwischen dem ersten knoten und dem begin des blocks noch platz ist...

            {
                node *temp = reinterpret_cast<node *>(mem);
                temp->size = size;
                temp->last = 0;
                temp->next = p;
                p->last = temp;
                p = temp;
                return p + 1;
            }
            else
// <HIER MUSS DER FEHLER LIEGEN ======================================>

            {
                node *a = p;
                node *b = p->next;
                while (b)
                // bis zum ende der liste suchen

                {
                    if ((reinterpret_cast<char *>(b) - reinterpret_cast<char *>(a) - a->size - sizeof(node)) >= (size + sizeof(node)))
                    // wenn zwischen 2 noch platz ist

                    {
                        node *temp = reinterpret_cast<node *>(reinterpret_cast<char *>(a) + a->size + sizeof(node));
                        temp->size = size;
                        temp->next = b;
                        temp->last = a;
                        a->next = temp;
                        b->last = temp;
                        return temp + 1;
                    }
                    b = b->next;
                }
                unsigned used = (reinterpret_cast<char *>(a) - mem) + a->size + sizeof(node);
                if ((used + size + sizeof(node)) > memsize)
                    return 0;
                
                node *temp = reinterpret_cast<node *>(reinterpret_cast<char *>(a) + a->size + sizeof(node));
                temp->size = size;
                temp->next = 0;
                temp->last = a;
                a->next = temp;
                return temp + 1;
            }
// </HIER MUSS DER FEHLER LIEGEN ======================================>

        }
    }
    void dealloc(void *ptr)
    {
        node *n = reinterpret_cast<node *>(ptr) - 1;    // listeninfos sind vor den benutzerdaten

        if (n->next)
        {
            if (n->last)
            {
                n->last->next = n->next;
                n->next->last = n->last;
            }
            else
                n->next->last = 0;
        }
        else
        {
            if (n->last)
                n->last->next = 0;
            else
                p = 0;
        }
    }
    //.................

    char *mem;          // der speicherblock

    unsigned memsize;   // gesammtgröße des speicherblocks 'mem'

    node *p;            // startknoten, zeigt auf das erste element in der liste


das '+1' bei der rückgabe liegt daran, dass der allokierte speicher
genau nach den listendaten liegt, also 'sizeof(node)' bytes weiter.

der fehler:

wenn ich mehrere objekte allokiere, scheinen sich einige speicher
bereiche zu überlappen. komischerweise stürzt er jedoch nicht ab
obwohl dabei ja auch die listendaten überschrieben werden müssten.

ein einzelnes element zu erstellen klappt ohne probleme und im debugger
konnte ich auch keine üperlappenden berieche finden.

der große speicherblock wird auch korrekt erzeugt

hoffe einer findet den fehler :cry:
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

"Es ist nicht undicht, es läuft über" - Homer Simpson

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

2

15.10.2008, 19:07

Ein Fehler den ich auf die Schnelle gefunden habe ist dieser hier:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
while (b)
            // bis zum ende der liste suchen

            {
                if ((reinterpret_cast<char *>(b) - reinterpret_cast<char *>(a) - a->size - sizeof(node)) >= (size + sizeof(node)))
                // wenn zwischen 2 noch platz ist

                {
                    node *temp = reinterpret_cast<node *>(reinterpret_cast<char *>(a) + a->size + sizeof(node));
                    temp->size = size;
                    temp->next = b;
                    temp->last = a;
                    a->next = temp;
                    b->last = temp;
                    return temp + 1;
                }
        a = b; // <-- vergessen!!!

                b = b->next;
            }


Deine dealloc Methode ist übrigens falsch. Sie funktioniert nicht für das erste Element.
@D13_Dreinig

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

3

16.10.2008, 09:48

Zitat

ich habe ein problem mit einem speichermanager. weil ich viele kleine
speicherblöcke regelmäßig anfordere und freigebe, habe ich mir einen
eigenen geschrieben, der den speicher nicht sofort zurückgibt sondern
nur als frei markiert

Dein Vorhaben ganz in Ehren, aber das ist ein Grund, warum es Allocatoren gibt. Ich würde eine Benutzung eines eigen geschriebenen allocator bevorzugen, als eine ganz selber geschriebene Liste.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

4

16.10.2008, 09:51

Zitat von »"drakon"«


Dein Vorhaben ganz in Ehren, aber das ist ein Grund, warum es Allocatoren gibt. Ich würde eine Benutzung eines eigen geschriebenen allocator bevorzugen, als eine ganz selber geschriebene Liste.


Er hat doch einen allocator geschrieben... Was willst du uns mitteilen? :)
@D13_Dreinig

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

5

16.10.2008, 10:01

Zitat von »"David_pb"«


Er hat doch einen allocator geschrieben... Was willst du uns mitteilen? :)

:oops:
Sorry. Ja. Ich habe irgendwie nur die ersten paar Zeilen durchgelesen und mal an dem kurz überflogenen Code gedacht, dass das ein Ausschnitt aus einer eigenen Liste ist. Wollte mir den Code ein wenig später zu gemüte führen. :)

Gotbread

Alter Hase

  • »Gotbread« ist der Autor dieses Themas

Beiträge: 421

Beruf: Student (Etechnik) + Hiwi

  • Private Nachricht senden

6

16.10.2008, 12:24

Zitat von »"David_pb"«


a = b; // <-- vergessen!!!

Neeeeeeein da war der fehler... eine einzige zeile... naja ok es tuts

die dealloc tuts. das erste element ist das einzige das 100%
funktioniert, weil wenn nur ein element existiert, zeigt 'p' auf dieses. nachbarn hat es keine. um es aus der liste zu entfernen muss man nur 'p' auf 0 setzen

löschen geht ja nicht. der speicher wird noch gebraucht :)

und es ist eine eigene liste. mit der kleinen änderung funktioniert sie
perfekt :)
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

"Es ist nicht undicht, es läuft über" - Homer Simpson

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

7

16.10.2008, 12:47

Zitat

und es ist eine eigene liste.

:lol:
Dann habe ich dich doch nicht falsch verstanden. :)

Zitat

mit der kleinen änderung funktioniert sie
perfekt

Mit dieser Aussage wäre ich mal vorsichtig. ;) - Ich bin einfach mal so frech und sage, dass sie das nicht ist. Aber schlussendlich ist es deine Entscheidung. :)
btw:
Andrei Alexandrescu hat in seinem Buch "Modern C++ Design" ein recht interessantes Kapitel über einen Small Object Allocator geschrieben. (respektive in der Loki Bibliothek implementiert). Ev. einen Blick wert. ;)

Gotbread

Alter Hase

  • »Gotbread« ist der Autor dieses Themas

Beiträge: 421

Beruf: Student (Etechnik) + Hiwi

  • Private Nachricht senden

8

16.10.2008, 13:41

perfekt isse natürlich nicht, aber sie macht das was ich will und das auch noch schnell :)
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

"Es ist nicht undicht, es läuft über" - Homer Simpson

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

9

16.10.2008, 13:48

Zitat von »"Gotbread"«


die dealloc tuts. das erste element ist das einzige das 100%
funktioniert


Nein! Der Deallocator ist falsch!
@D13_Dreinig

Gotbread

Alter Hase

  • »Gotbread« ist der Autor dieses Themas

Beiträge: 421

Beruf: Student (Etechnik) + Hiwi

  • Private Nachricht senden

10

16.10.2008, 13:51

warum ?

edit:

ok sie üperprüft nicht auf null und ist nicht gegen das löschen von anderen
zeigern gesichert. aber wenn man der methode keinen quatsch gibt
deallokiert sie wie sie soll. auch das erste element
Mfg Goti
www.gotbread.bplaced.net
viele tolle spiele kostenlos, viele hardware-basteleien :)

"Es ist nicht undicht, es läuft über" - Homer Simpson

Werbeanzeige