È più sottile di quanto suggeriscano le altre risposte. Non esiste una divisione assoluta tra i dati nello stack e i dati nell'heap in base a come lo dichiari. Per esempio:
std::vector<int> v(10);
Nel corpo di una funzione, che dichiara un vector
(array dinamico) di dieci numeri interi nello stack. Ma lo spazio di archiviazione gestito da vector
non è in pila.
Ah, ma (le altre risposte suggeriscono) la durata di quella memoria è limitata dalla durata della vector
stessa, che qui è basata sullo stack, quindi non fa differenza come è implementata: possiamo solo trattarla come un oggetto basato sullo stack con semantica dei valori.
Non così. Supponiamo che la funzione fosse:
void GetSomeNumbers(std::vector<int> &result)
{
std::vector<int> v(10);
// fill v with numbers
result.swap(v);
}
Quindi qualsiasi cosa con una swap
funzione (e qualsiasi tipo di valore complesso dovrebbe averne una) può servire come una sorta di riferimento riassociabile ad alcuni dati di heap, in un sistema che garantisce un unico proprietario di quei dati.
Pertanto il moderno approccio C ++ consiste nel non memorizzare mai l'indirizzo dei dati dell'heap in variabili puntatore locali nude. Tutte le allocazioni di heap devono essere nascoste all'interno delle classi.
Se lo fai, puoi pensare a tutte le variabili nel tuo programma come se fossero semplici tipi di valore e dimenticare del tutto l'heap (tranne quando si scrive una nuova classe wrapper simile a un valore per alcuni dati dell'heap, che dovrebbe essere insolito) .
Devi semplicemente conservare un po 'di conoscenza speciale per aiutarti a ottimizzare: dove possibile, invece di assegnare una variabile a un'altra in questo modo:
a = b;
scambiali in questo modo:
a.swap(b);
perché è molto più veloce e non genera eccezioni. L'unico requisito è che non è necessario b
continuare a mantenere lo stesso valore (invece otterrà a
il valore di, che verrebbe cestinato a = b
).
Lo svantaggio è che questo approccio costringe a restituire valori dalle funzioni tramite parametri di output invece del valore di ritorno effettivo. Ma lo stanno risolvendo in C ++ 0x con riferimenti rvalue .
Nelle situazioni più complicate di tutte, porteresti questa idea all'estremo generale e utilizzeresti una classe puntatore intelligente come quella shared_ptr
che è già in tr1. (Anche se direi che se ti sembra di averne bisogno, probabilmente sei uscito dal punto debole di applicabilità dello Standard C ++.)