Riesen-Problem mit gelöschten Objekten und Referenzen...
-
Ich habe eine ARRAY-Struktur erstellt. Mit zahlreichen Funktionen dazu. Dieses ARRAY hat spezielle Features, weswegen ich keine "Standard-Arrays" mit malloc erstellen konnte...
Hier paar Deklarationen
typedef struct { int length; int depth; void* memory; } array; array* array_create(int length, int depth); void array_delete(array* a); ... viele weitere Funktionen...
So nun habe ich auch noch OBJECT-Struktur. Es können beliebig viele Objekte existieren... Jedes Objekt hat zudem eine "Liste". Diese Liste ist im Prinzip ein mit malloc erstellter Speicherblock wo Pointer von ARRAYS gespeichert sind.
Hier paar Deklarationen
typedef struct { int count; array** list; } object; object* object_create(); array* object_getarray(object* obj, int index); int object_addarray(object* obj); void object_deletearray(object* obj, int index); ... viele weitere Funktionen...
Mit Hilfe der Funktion object_getarray() kann ich einen Arrayzeiger aus dem Objekt holen und so kann ich alle ARRAY-Funktionen verwenden...
Das Problem #1 ist nun was ich habe: man kann nun auch dieses array löschen - und in dem Fall hätte ich einen toten pointer in meiner Objekt-Liste ;-/
Da zudem die Liste dauernd geändert wird, kann ich nicht einfach sagen: wenn array gelöscht wird, dann lösche den entsprechenden Pointer X aus der Liste...
Meine Notlösung war nun diese Funktionen zu ändern:
array** object_getarray(int index);
void array_delete(array** a);Es wird ein pointer auf pointer zurückgeliefert. Und der entsprechende Pointer in der Liste wird dann beim Aufruf der Funktion array_delete() auf 0 gesetzt...
Das Problem #2:
array** a = object_getarray(myobject, int index); /*ok*/ array* b = *a; /*hole den array-zeiger*/ array** c = &b /*nun setzte den zeiger auf meine variable b*/;
In dem Fall hätte ich den Pointer "umgebogen" und mein array-Eintrag wird nicht auf 0 gesetzt, wenn ich nun lösche - HILFE!!!
Ist das den die gängige Praxis wie man sowas lösen könnte? Oder hat hier jemand einen Trick auf Lager? Ach ja - diese Arrays setzte ich für zich andere Strukturen ebenfalls ein...
-
TheShadow2000 schrieb:
Das Problem #1 ist nun was ich habe: man kann nun auch dieses array löschen - und in dem Fall hätte ich einen toten pointer in meiner Objekt-Liste ;-/
spendier den array-objekten doch ein flag, das kennzeichnet ob sie gelöscht werden dürfen (z.b. wenn keiner eine referenz drauf hat) oder nicht...
:xmas2:
-
und woher weiß ich dann ob es irgendwo noch eine referenz gibt?
genau so könnte ich den flag dann manuell "versauen" und dann zum löschen bringen - dann wäre irgendwo weiterhin eine referenz dazu...
EDIT:
Als Beispiel wollte ich mir mal die Funktion aus SDL angucken:void SDL_FreeSurface (SDL_Surface *surface);
und irgendwo im Code:
if ( --surface->refcount > 0 ) { return; }
dann muß man extrem sauber arbeiten und auch darauf achten, dass refcount immer aktualisert wird.... was aber wenn man 2x array_delete() ausführt? dann ist der count futsch...
nein ich suche was totsicheres...
-
ALSO... je mehr ich nachdenke, desto mehr Sinn macht sowas wie refcount...
Aber ich werde es etwas anders machentypedef struct { /*Jede Struktur hat sowas*/ char refcount; /*Array-Eigenschaften*/ int length; int depth; void* memory; } array;
Array-Erstell und Lösch-Funktionen ändern niemals refcount-Eigenschaft. Diese ist Standardmässig 0.
In meinen eigenen Funktionen aus meiner Library werde ich jedoch bei Referenzierung den Wert erhöhen und vor dem Löschen verkleinern.
So... Dadurch ist garantiert, dass zumindest meine Library sauber läuft. Wenn nun der User einfach so ein array löscht, ohne den Wert zu verkleinern, dann passiert GAR NIX - außer der Wert steht bei 0!
Da Standardmässig alle Strukturen diesen Wert bei 0 stehen haben, werden diese auch normal gelöscht...
-
Das Prinzip von Referenz-Counting ist doch, das man für jede neue Referenz den Zähler erhöht und für jede Referenz die man zerstört den Zähler verringert und wenn er 0 ist, dann löscht man das Ding.
typedef struct { uint8_t ref_count; void *sth; } sth; sth *create_sth() { sth *ret = malloc(sizeof(sth)); sth->ref_count = 1; return sth; } sth *get_reference_on_sth(sth *s) { ++s->ref_count; return s; } void destroy_sth(sth *s) { if(--s->ref_count == 0) free(s); }
btw. nimmt man für Längenangaben size_t oder zumindest einen unsigend-Typ!
-
hm ja... dein Code hat ein Problem:
wenn du sagen wir mal mehrere referenzen hast und du aber mogels und 2x destroy_sth() aufrufs, dann hast du
- objekt gelöscht
- noch irgendwo referenzen liegen
- speicherfehler
somit ist es nicht idiotensicher - was meine library aber sein soll
-
Mogeln kann man bei C eh immer. Daher muss man davon ausgehen, dass der Benutzer nicht mogelt... (Wenn er mogeln will, kann er eh alles erreichen)
-
ja wenn man das so sagt, dann kann man auch sagen C ist von design so ausgelegt, dass irg. speicherfehler vorprogrammiert sind...
-
boehm GC