At most; my largest object would probably be a QString of maybe a
million characters.
sizeof(QString)
è 8 byte su sistemi a 64 bit, non importa quanto grande o piccolo sia il suo contenuto, perché i contenuti sono sempre allocati nell'heap, come nel caso di std::vector
. QString
è effettivamente solo un handle per la memoria sull'heap. Quindi, anche se crei un oggetto QString
nello stack e inserisci un milione di caratteri, è comunque sufficiente utilizzare 8 byte di spazio di stack al massimo, se non si vive direttamente in un registro.
Se hai tentato di allocare un milione di caratteri unicode nello stack, in molti casi questo richiederebbe un overflow.
Nella maggior parte del normale tipo di codice C ++ le persone scrivono, in genere non è necessario pensare alla distinzione tra stack e heap, dal momento che è completamente distratto da te con le strutture dati standard che usi. La distinzione è generalmente più se si usa, diciamo, unique_ptr
o meno nell'implementazione di una classe. In tal caso, ciò implica l'overhead dell'heap aggiuntivo, un ulteriore livello di riferimento indiretto e una frammentazione della memoria.
Se lavori con oggetti che non gestiscono la propria memoria separatamente nell'heap, come se volessi usare std::array<T, N>
nello stack, allora forse un intervallo ragionevole (solo un numero approssimativo e grezzo da utilizzare di) è in genere nell'intervallo tra centinaia di byte e forse un paio di kilobyte per una funzione che non viene chiamata in modo ricorsivo o che chiama altre funzioni che allocano una grande quantità di spazio di stack per essere ragionevolmente sicuri contro gli overflow dello stack sulla maggior parte delle macchine desktop e sistemi operativi almeno. Se si tratta di un array di numeri interi a 32 bit, potrei usare l'heap se ce ne sono più di 128 da archiviare (più di 512 byte), ad esempio, a quel punto potresti invece utilizzare std::vector
. Esempio:
void some_func(int n, ...)
{
// 'std::array' is a purely contiguous structure (not
// storing pointers to memory allocated elsewhere), so
// here we are actually allocating sizeof(int) * 128
// bytes on the stack.
std::array<int, 128> stack_array;
int* data = stack_array.data();
// Only use heap if n is too large to fit in our
// stack-allocated array of 128 integers.
std::vector<int> heap_array;
if (n > stack.size())
{
heap_array.resize(n);
data = heap_array.data();
}
// Do stuff with 'data'.
...
}
Per quanto riguarda la semantica del movimento, applicherei una regola simile perché è in realtà abbastanza economico copiare in profondità anche 512 byte se si tratta semplicemente di copiare la memoria dallo stack allo stack o da due regioni di memoria con una località temporale elevata. Anche se hai una grande classe, Foo
, con una dozzina di membri di dati in cui sizeof(Foo)
è come un enorme 256 byte, non la userei così tanto per allocare il suo contenuto sull'heap se può essere evitato. Normalmente stai perfettamente bene se la decisione di utilizzare l'heap o meno si basa più su cose diverse dalle prestazioni, come evitare gli overflow dello stack e modellare strutture di dati di dimensioni variabili (che implicano l'heap a meno che non siano ottimizzati per casi comuni che coinvolgono piccole dimensioni , come piccole ottimizzazioni di stringhe che evitano l'allocazione heap extra per stringhe piccole ma utilizzano l'allocazione heap extra per quelle grandi), consentendo la proprietà condivisa con shared_ptr
, utilizzando un pimpl per ridurre le dipendenze in fase di compilazione o allocando sottotipi per il polimorfismo dove potrebbe essere ingombrante per evitare allocazioni di heap in questi casi.