2009-03-06 11 views
7

Stavo cercando una regola empirica per allocare oggetti su stack o heap in C++. Ho trovato molte discussioni qui su SO. Molte persone hanno detto, si tratta della vita di un oggetto. Se è necessaria una durata maggiore rispetto all'ambito della funzione, inserirla nell'heap. Questo ha perfettamente senso.Come identificare se un oggetto deve essere in pila o no?

Ma ciò che mi ha reso confuso è, dicevano molte persone, allocare oggetti da impilare se sono piccoli. Se gli oggetti sono grandi, mettili in pila. Ma nessuno di loro ha detto come identificare un oggetto è grande o no?

ho le seguenti domande,

  1. Come identificare un oggetto è grande o no?
  2. Quale sarà la dimensione massima dello stack? Ogni sistema operativo avrà diverse dimensioni dello stack?
  3. Ho una classe wrapper che include vector<string>. Avrà circa 100 articoli. Farà un overflow dello stack se alloco questa classe in una pila? Ho provato questo, ma ha funzionato perfettamente. Non sono sicuro che sto facendo qualcosa di sbagliato.

risposta

10

Beh, in primo luogo i vettori (e tutte le classi di container STL) allocano sempre dall'heap in modo da non doversi preoccupare di ciò. Per qualsiasi contenitore con dimensioni variabili è praticamente impossibile utilizzare lo stack.

Se si pensa a come funziona l'allocazione dello stack (in fase di compilazione, basicamente incrementando un puntatore per ciascun oggetto), dovrebbe essere chiaro che la memoria vettoriale proviene dall'heap.

std::vector<int> myInts; 
std::string myString; 
SomeOther Class; 

// this memory must come from the heap, there's no way it 
// can now be allocated on the stack since there are other 
// objects and these parameters could be variable 
myString = "Some String"; 
myInts.reserve(256); 

A meno che non ci si trova in una funzione ricorsiva è possibile inserire diversi kilobyte di dati nello stack senza molta preoccupazione. Le dimensioni dello stack sono controllate dal programma (non dal sistema operativo) e il valore predefinito tende a variare da 32kb a 1mb. La maggior parte dei software desktop arriva nella gamma 1mb.

Gli oggetti singoli non sono quasi mai un problema. In generale, saranno abbastanza piccoli per lo stack o verranno allocati internamente dall'heap.

Se gli oggetti sono locali per una funzione, metterli in pila. Se non li metti sul mucchio.

Utilizzare l'heap per i buffer di grandi dimensioni allocati per caricare/ordinare/manipolare i dati.

+0

... per caricare/ordinare/manipolare i dati * manualmente *. Se stai usando STL per fare il lavoro per te, non c'è bisogno di passare attraverso il problema e preoccuparsi di nuovo/cancella. Basta assegnare in pila lì. – strager

+0

Grazie per la risposta. Hai qualche documento in cui dice che il vettore assegna i contenuti su un mucchio? –

+0

Deve funzionare per .resize() ecc. –

4

In base allo stack MSDN, il valore predefinito è 1mb. (Questo è ovviamente per Msdev).

Come si può vedere dall'articolo, è possibile modificare le dimensioni dello stack in fase di compilazione con il flag/F.

Penso che la tua prima linea guida per l'utilizzo dello stack vs dell'heap sia piuttosto accurata, con la qualifica che se la variabile di scope temporanea è più grande di un mb, incollala nell'heap (e probabilmente chiedi perché stai allocando così tanta memoria per un breve periodo di tempo in primo luogo).

1

Come identificare un oggetto è grande o no?

Dipende dalla combinazione del compilatore/piattaforma. Non esiste un unico limite. I compilatori ti permettono spesso di ottimizzarlo.

Quale sarà la dimensione massima dello stack? Ogni sistema operativo avrà diverse dimensioni dello stack?

Dipende principalmente come sopra. L'unica cosa che hai meno controllo della messa a punto.

Ho una classe wrapper che avvolge il vettore. Avrà circa 100 articoli. Farà un overflow dello stack se alloco questa classe in una pila? Ho provato questo, ma ha funzionato perfettamente. Non sono sicuro che sto facendo qualcosa di sbagliato.

Funzionerà finché il requisito di memoria totale di questo wrapper e di altri oggetti in tale blocco non supererà le dimensioni del frame dello stack. Che a sua volta dipende dalla stringa media sie.

Una buona idea è quella di passare attraverso un debugger e vedere gli indirizzi dello stack - che ti darà un inizio della larghezza in una certa misura. E la documentazione.

1

Un altro punto citerò è che, poiché vector<> deve essere in grado di ridimensionare se stessa, se cresce abbastanza grande (vedi sotto) deve utilizzare l'heap per memorizzare i propri oggetti contenuti, anche se la stessa è vector<> dichiarato come variabile dello stack.

[EDIT] Come sottolinea Motti in un commento, è possibile che vector<> si riserva una piccola quantità di spazio all'interno il suo oggetto stack allocato come un'ottimizzazione per i piccoli vettori. In tal caso, il lavoro con i vettori abbastanza piccoli da adattarsi a questo spazio non richiederà alcuna allocazione dell'heap. (Questo spazio pre-allocato deve essere piuttosto piccolo per evitare di sprecare spazio quando si lavora con vettori più piccoli.) Indipendentemente da ciò, se il vettore diventa sufficientemente grande, richiederà (ri) allocazione sull'heap.

+1

Non è vero, può utilizzare un buffer iniziale che fa parte dell'oggetto (come l'ottimizzazione della stringa piccola). – Motti

+0

Buon punto. Ho aggiornato il post per chiarire le cose. –

3

L'unico modo in cui è possibile allocare oggetti di grandi dimensioni nello stack consiste nell'avere un array vecchio stile coinvolto in qualche punto. Per esempio:

void f() { 
    char a[1000000]; // big object on the stack 
} 

struct A { 
    char c[1000000]; 
}; 

void g() { 
    A a;  // another big object on the stack 
} 

Se non si utilizzano gli array (e non dovrebbe), allora la maggior parte delle cose sarà assegnato per voi sul mucchio:

void h() { 
    std::string s(100000); 
} 

quanto sopra alloca alcuni byte su lo stack per puntatori, informazioni sulla dimensione, ecc. e quindi alloca lo storage effettivo sull'heap.

Quindi smettere di preoccuparsi! Probabilmente stai facendo le cose bene!

+0

Questi non sono "matrici vecchio stile". Sono matrici. Non dovresti mai usarli e dovresti sapere come (e quando) usarli. – strager

+0

Grazie per la risposta. Ma come mai l'ultimo codice che hai dato va in heap? Intendi dire che std :: string usa internamente l'heap per mantenere il contenuto? –

+0

@Appu Sì, precisamente –

1

1. Come identificare un oggetto è grande o no?

Uso "sizeof"

class c { 
    std::vector<std::string> s; 
}; 

int size = sizeof (c);

Sulla mia macchina "dimensione" è di 16 byte.

2. Quale sarà la dimensione massima dello stack? Ogni sistema operativo avrà diverse dimensioni dello stack?

Non si può dire, ma non è sicuramente un buon posto per allocare masse di dati.

3. Ho una classe wrapper che avvolge il vettore. Avrà circa 100 articoli. Farà un overflow dello stack se alloco questa classe in una pila? Ho provato questo, ma ha funzionato perfettamente. Non sono sicuro che sto facendo qualcosa di sbagliato.

No. std :: vector alloca i 100 elementi nell'heap.