Christian Seiler: C++ und der Heap

Beitrag lesen

Hallo johnny,

Wenn ich für das ganze jetzt eine Klasse schreibe die all das Automatisch erledigt?

Wozu? Was bringt Dir das? Wenn Du eine Unterfunktion aufrufen willst und nicht willst, dass die etwas auf dem Heap alloziert, dann alloziert doch in der AUFRUFENDEN Funktion etwas auf dem Stack.

Beispiel:

int getXYZ (char *buf, size_t bufsize /*, weitere Parameter */) {  
   // erstelle IRGENDWIE einen Wert und schreibe ihn in den Puffer  
   // und stelle sicher, dass bufsize nicht überschritten wird  
   // (muss nicht strncpy sein, kann auch etwas anderes wie z.B.  
   // snprintf o.ä. sein)  
   strncpy (buf, /* der wert */, bufsize);  
   // z.B. 0 == erfolg  
   return 0;  
}

Damit has Du dann eine Funktion, der Du einen bestehenden Puffer und dessen Maximalgröße übergeben kannst, die ihn irgendwie füllt (was auch immer Du machen willst).

Wenn Du nun die Funktion aufrufen willst, kannst Du ganz einfach folgendes machen:

void andereFunktion (void) {  
  char buf[1001];  
  int ret = getXYZ (buf, 1001 /*, weitere Parameter */);  
  // irgendwas mit ret und buf anstellen  
  // funktion beendet sich, buf wird automatisch zerstört  
  // da er jedoch in DIESER funktion alloziert wurde und nicht in  
  // getXYZ, fliegt Dir auch nichts um die Ohren  
}

Wozu also extra eine Klasse dafür erstellen?

Bzw. wenn Du Dir extra eine Klasse für so etwas erstellen willst, dann würde ich eher die Methode empfehlen, die APR verwenden. APR ist die Apache Portabel Runtime und ist eine C-Bibliothek. Allerdings lässt sich das Grundprinzip der Speicherverwaltung, die diese nutzt, auch auf C++ übertragen, müsstest Du halt selbst programmieren (außer Du findest irgendwo bereits eine vorgefertige Bibliothek dafür). Das Konzept von APR sind sogenannte "Memory Pools". Bei Subversion, das auch APR verwendet, gibt's ne nette Einführung für diese Memory Pools (http://svnbook.red-bean.com/en/1.1/ch08s05.html) - allerdings ist die natürlich in C.

In C++ würdest Du halt von der API her im einfachsten Fall sowas in der Art machen:

class MemoryPool {  
  /* private-gedöns */  
  public:  
    MemoryPool ();  
    ~MemoryPool ();  
    void *alloc (size_t bytes);  
};

Was würde die Implementierung von alloc() machen? Sie würde auf irgend eine Weise einen Speicherbereich der Größe »bytes« allozieren und den dann zurückgeben. Das Programm könnte den dann verwenden. Freigegeben werden würde der Speicherbereich dann erst im Destruktor, der ALLE von diesem Objekt aus allozierte Speicherbereiche zerstören würde. Ein Beispiel für die Verwendung sähe dann so aus:

void tuIrgendwas (void) {  
  MemoryPool pool;  
  // 10-zeichen große zeichenkette hier anlegen  
  char *zeiger1 = (char *) pool.alloc (10 * sizeof (char));  
  // zeichenkette aus der unterfunktion anlegen lassen  
  char *zeiger2 = getXYZ (&pool /*, weitere Parameter */);  
  // tu irgendwas  
  // am Ende wird pool zerstört und damit auch alle allozierten Zeiger  
}

Und getXYZ sähe dann so aus:

char *getXYZ (MemoryPool *pool /*, weitere Parameter */) {  
  // rechne irgendwas  
  char *ergebnis = pool->alloc (1001 * sizeof (char));  
  strncpy (ergebnis, /* wert */, 1001);  
  return ergebnis;  
}

Das ganze lässt sich natürlich auch noch auf so Dinge wie "Sub-Pools" erweitern, d.h. Pools, die "Kinder" von anderen Pools sind. Schau Dir einfach mal die Apache Portable Runtime an (http://apr.apache.org/) - die kann zwar noch deutlich mehr als Memory Pools und vieles davon brauchst Du in C++ nicht (weil's da wg. OOP besseres gibt und APR ein C-Projekt ist), aber Du kannst Dir da wirklich mal die Pools ansehen.

Ich habe Dir hier jetzt nur mal das Grobkonzept dargelegt, der eigentliche Witz an Memory Pools ist jedoch die Performance - d.h. sie wurden ursprünglich entwickelt, um die Performance gegenüber new / malloc zu steigern. Wenn Du diese Pools nach meiner Beschreibung sehr naiv implementieren würdest, dann hättest Du zwar die Vorteile, was das Programmieren angeht, aber die Performance wäre schlechter als die von new / malloc. Wenn Du dagegen Zeit investierst, Dir ein brauchbares Konzept für diese Pools zu überlegen, dann können die sogar noch schneller sein, als new  / malloc - und dann hättest Du zwei Vorteile auf einmal. Da sich andere Leute schon sehr viele schlaue Gedanken zu dem Thema gemacht haben, empfielt es sich in meinen Augen, mal nach dem Stichwort zu suchen und zu sehen, welche Lösungen es da bereits gibt (beachte jedoch, das manche Leute einen einzigen GLOBALEN Memory-Pool für die ganze Applikation wollen, um einfach nur mehr Performance zu bekommen, während andere Leute multiple Pools wollen, um eben innerhalb von Funktionen Speicher schmerzfrei allozieren zu können).

Viele Grüße,
Christian