Zusammenfassung Zuteilungen und Deallocators für jeden Typ. eine Typdefinition
gegeben
typedef struct foo
{
int x;
double y;
char *z;
} Foo;
eine allocator Funktion
Foo *createFoo(int x, double y, char *z)
{
Foo *newFoo = NULL;
char *zcpy = copyStr(z);
if (zcpy)
{
newFoo = malloc(sizeof *newFoo);
if (newFoo)
{
newFoo->x = x;
newFoo->y = y;
newFoo->z = zcpy;
}
}
return newFoo;
}
eine Kopierfunktion
Foo *copyFoo(Foo f)
{
Foo *newFoo = createFoo(f.x, f.y, f.z);
return newFoo;
}
und eine deallocator Funktion
void destroyFoo(Foo **f)
{
deleteStr(&((*f)->z));
free(*f);
*f = NULL;
}
Beachten Sie, dass createFoo()
wiederum ruft eine erstellen copyStr()
Funktion, die für das Zuweisen von Speicher für und das Kopieren des Inhalts einer Zeichenfolge verantwortlich ist. Beachten Sie auch, dass, wenn copyStr()
fehlschlägt und einen NULL zurückgibt, newFoo
nicht versucht, Speicher zuzuweisen und einen NULL zurückzugeben. In ähnlicher Weise ruft destroyFoo()
eine Funktion auf, um den Speicher für z vor dem Freigeben des Rests der Struktur zu löschen. Schließlich setzt destroyFoo()
den Wert von f auf NULL.
Der Schlüssel hier ist, dass der Allokator und Deallocator die Verantwortung für andere Funktionen delegieren, wenn Elementelemente auch Speicherverwaltung erfordern. So, wie Sie Ihre Arten komplizierter, können Sie diese Verteilern wie so wiederverwenden:
typedef struct bar
{
Foo *f;
Bletch *b;
} Bar;
Bar *createBar(Foo f, Bletch b)
{
Bar *newBar = NULL;
Foo *fcpy = copyFoo(f);
Bletch *bcpy = copyBar(b);
if (fcpy && bcpy)
{
newBar = malloc(sizeof *newBar);
if (newBar)
{
newBar->f = fcpy;
newBar->b = bcpy;
}
}
else
{
free(fcpy);
free(bcpy);
}
return newBar;
}
Bar *copyBar(Bar b)
{
Bar *newBar = createBar(b.f, b.b);
return newBar;
}
void destroyBar(Bar **b)
{
destroyFoo(&((*b)->f));
destroyBletch(&((*b)->b));
free(*b);
*b = NULL;
}
Offensichtlich ist dieses Beispiel geht davon aus, dass die Mitglieder nicht über eine Lebensdauer außerhalb ihrer Container. Das ist nicht immer der Fall, und Sie müssen Ihre Schnittstelle entsprechend gestalten. Dies sollte Ihnen jedoch einen Eindruck vermitteln, was zu tun ist.
Dadurch können Sie Speicher für Objekte in einer konsistenten, wohldefinierten Reihenfolge zuordnen und freigeben, was 80% des Kampfes in der Speicherverwaltung ausmacht. Die anderen 20% stellen sicher, dass jeder Allocator-Aufruf durch einen Deallocator ausgeglichen wird, welcher der wirklich harte Teil ist.
bearbeiten
die Anrufe an die delete*
Funktionen verändert, so dass ich die richtigen Typen vorbei bin.
Dieser lange Zeit C-Codierer wechselte zu C++, und das Problem ging weg. –
@Neil Butterworth: Entweder das oder (öfter) das Problem wurde viel schlimmer. – sharptooth
@sharptooth: Ich bin kein Fan von C++, aber es kümmert sich um eine ganze Reihe von Speicherverwaltungsproblemen für Sie. Ich lasse natürlich die wirklich harten zurück. :-) – JesperE