Newsgroup: it.comp.lang.c++
Titolo: Allocazione su Stack

Salve a tutti,
ho costruito un tipo numerico custom che contiene dei puntatori ai quali 
vengono allocate delle aree di memoria utilizzando il classico new .
Il problema che si ha con un approccio di questo tipo e' una grande 
frammentazione di memoria  molto piu' di quanto si avrebbe utilizzando dei 
tipi numerici "semplici" .
Una causa principale di questo problema e' che l'allocazione viene sempre 
effettuata sullo heap anche per variabili dichiarate in locale nelle routine 
invece di sfruttare in modo piu' corretto lo stack.
Volevo chiedere un vostro parere su quale sia la soluzione migliore in 
gestire differenti tipi di allocazione stack o heap in modo piu' possibile 
automatizzato.
Grazie, Denis. 

 automatizzato.
Se le classi che allochi con new sono molto piccole, perché le allochi 
con new e non le inserisci direttamente nell'oggeto?
Se invece sono grosse è giusto allocarle sullo heap. Come fai a sapere 
che lo heap è frammentato? Hai finito la memoria?
E.

Denis ha scritto:

Potresti crearti un allocatore ad hoc per oggetti piccoli.
Ti allochi un pool contiguo del numero di oggetti che ti servono
tutti all'inizio, li usi e alla fine deallochi il tutto.
ciao

 tutti all'inizio, li usi e alla fine deallochi il tutto.
Ma questo normalmente lo fa già il gestore della memoria. Siamo sicuri 
che sia veramente necessario farselo da sé?
E.

 che sia veramente necessario farselo da sé?
Per oggetti molto piccoli e uniformi potrebbe proprio essere.
Per esempio implementazioni di malloc piuttosto diffuse (e chi ci sta
sopra) non allocano *mai* meno di 16 byte (iirc 32 se siamo a 64 bit) +
un overhead per chunk di 4-8(8-16) bytes. Questo per il modo in cui sono
gestite le catene di chunks che costituiscono il free-store etc etc etc.
Mi riferisco all'implementazione 'classica' di Lea. Adesso qualcosa di
meglio dovrebbe girare, ma comunque resta il fatto che malloc (e new)
hanno requisiti di generalità (devono funzionare bene con tipi di tutte
le dimensioni, gestire frammentazione della memoria etc etc etc).
Il caso in cui si hanno oggetti di dimensione fissata si può IMHO
gestire in modo più efficiente. Detto questo, io *non* mi prenderei la
briga a meno di non avere scoperto di averne proprio bisogno.
IMHO la soluzione sensata è comunque quella di sparare sullo stack, nel
caso di OP. Sia per motivi di comodità che di efficienza.
-- 
cc = callcc {|cc| cc.call cc}; cc.call cc

Denis ha scritto:

La frammentazione della memoria non e' l'unico inconveniente. Si ha un 
forte rallentamento dovuto al fatto che l'allocazione su heap (new e 
delete) e' tipicamente molto piu' lenta dell'allocazione su stack.
Per rimediare a questi problemi, una possible soluzione, come ti e' gia' 
stato detto e' un allocatore personalizzato, ma una soluzione forse 
possibile e probabilmente piu' efficiente e' dichiarare dei 
sotto-oggetti invece che dei puntatori a oggetti.
Cioe' invece di scrivere:
class MyNumber {
   ...
private:
   char* buffer;
   MyNumberImpl* impl;
};
dovresti scrivere, per migliorare la velocita' del programma:
class MyNumber {
   ...
private:
   char buffer[N];
   MyNumberImpl impl;
};
Tuttavia, quest'ultima soluzione ha i seguenti difetti:
1) Tutto il codice cliente di MyNumber diventa cliente di MyNumberImpl, 
e quindi ogni modifica a quest'ultima classe comporta ricompilazioni 
massicce.
2) Puo' essere difficile ottenere la exception-safety.
3) Se il sotto-oggetto "impl" e' opzionale, cioe' e' necessario solo per 
alcuni oggetti sei comunque costretto ad allocarlo e a gestirlo.
4) Nella prima soluzione, la dimensione del buffer e' variabile in fase 
di esecuzione, mentre nella seconda sei costretto a definire una 
lunghezza massima in fase di compilazione.
5) Se i sotto-oggetti sono molto grandi, cioe' "sizeof impl" o N sono 
molto grandi, rischi uno stack overflow.
Una tecnica di compromesso, usata da alcune implementazioni di classi 
stringa, e' l'ottimizzazione di oggetti piccoli.
Consiste nel dichiarare sia un buffer di N elementi che un puntatore a 
un buffer dinamico, eventualmente in union. Se il numero di elementi 
richiesti per un oggetto e' minore o uguale a N, si usa il buffer di N 
elementi nell'oggetto senza effettuare allocazioni dinamiche.
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila