Dies ist eine sehr häufige C-Lösung, die ich für das Problem verwende und die möglicherweise hilfreich ist. Im Gegensatz zu VLAs besteht in pathologischen Fällen kein praktisches Risiko eines Stapelüberlaufs.
/// Used for frequent allocations where the common case generally allocates
/// a small amount of memory, at which point a heap allocation can be
/// avoided, but rare cases also need to be handled which may allocate a
/// substantial amount. Note that this structure is not safe to copy as
/// it could potentially invalidate the 'data' pointer. Its primary use
/// is just to allow the stack to be used in common cases.
struct FastMem
{
/// Stores raw bytes for fast access.
char fast_mem[512];
/// Points to 'fast_mem' if the data fits. Otherwise, it will point to a
/// dynamically allocated memory address.
void* data;
};
/// @return A pointer to a newly allocated memory block of the specified size.
/// If the memory fits in the specified fast memory structure, it will use that
/// instead of the heap.
void* fm_malloc(struct FastMem* mem, int size)
{
// Utilize the stack if the memory fits, otherwise malloc.
mem->data = (size < sizeof mem->fast_mem) ? mem->fast_mem: malloc(size);
return mem->data;
}
/// Frees the specified memory block if it has been allocated on the heap.
void fm_free(struct FastMem* mem)
{
// Free the memory if it was allocated dynamically with 'malloc'.
if (mem->data != mem->fast_mem)
free(mem->data);
mem->data = 0;
}
So verwenden Sie es in Ihrem Fall:
struct FastMem fm;
// `result` will be allocated on the stack if 'len <= 512'.
char* result = fm_malloc(&fm, len);
// send result over network.
...
// this function will only do a heap deallocation if 'len > 512'.
fm_free(&fm, result);
In diesem Fall wird der Stapel verwendet, wenn die Zeichenfolge in maximal 512 Byte passt. Andernfalls wird eine Heap-Zuordnung verwendet. Dies kann nützlich sein, wenn die Zeichenfolge beispielsweise in 99% der Fälle in maximal 512 Byte passt. Nehmen wir jedoch an, es gibt einen verrückten exotischen Fall, den Sie gelegentlich behandeln müssen, wenn die Zeichenfolge 32 Kilobyte lang ist und der Benutzer auf seiner Tastatur eingeschlafen ist oder so. Dadurch können beide Situationen problemlos bewältigt werden.
Die aktuelle Version, die ich in der Produktion verwende, hat auch eine eigene Version von realloc
undcalloc
so weiter sowie standardkonforme C ++ - Datenstrukturen, die auf demselben Konzept basieren, aber ich habe das zur Veranschaulichung des Konzepts erforderliche Minimum extrahiert.
Es hat den Vorbehalt, dass das Kopieren gefährlich ist, und Sie sollten keine Zeiger zurückgeben, die durch das Kopieren zugewiesen wurden (sie könnten ungültig werden, da die FastMem
Instanz zerstört wird). Es ist für einfache Fälle innerhalb des Bereichs einer lokalen Funktion gedacht, in denen Sie versucht wären, immer die Stapel- / VLAs zu verwenden, da in seltenen Fällen Puffer- / Stapelüberläufe auftreten können. Es ist kein Allokator für allgemeine Zwecke und sollte nicht als solcher verwendet werden.
Ich habe es tatsächlich vor langer Zeit als Antwort auf eine Situation in einer alten Codebasis mit C89 erstellt, in der ein ehemaliges Team dachte, dass es niemals passieren würde, wenn ein Benutzer einen Gegenstand mit einem Namen benennt, der mehr als 2047 Zeichen lang ist (vielleicht ist er auf seiner Tastatur eingeschlafen) ). Meine Kollegen haben tatsächlich versucht, die Größe der an verschiedenen Stellen zugewiesenen Arrays auf 16.384 zu erhöhen. Zu diesem Zeitpunkt hielt ich es für lächerlich und tauschte lediglich ein höheres Risiko eines Stapelüberlaufs gegen ein geringeres Risiko eines Pufferüberlaufs aus. Dies stellte eine Lösung dar, die sehr einfach zu installieren war, um diese Fälle zu beheben, indem nur ein paar Codezeilen hinzugefügt wurden. Dies ermöglichte es, den allgemeinen Fall sehr effizient zu handhaben und den Stapel dennoch zu nutzen, ohne die verrückten seltenen Fälle, bei denen der Haufen die Software zum Absturz brachte. Wie auch immer, ich' Wir fanden es seitdem auch nach C99 nützlich, da VLAs uns immer noch nicht vor Stapelüberläufen schützen können. Dieser kann aber noch Pools aus dem Stack für kleine Zuweisungsanfragen bilden.