2012-07-13 13 views
12

Ok, quindi sono molto nuovo alla programmazione C++, e ho cercato un paio di giorni per una risposta decisiva per questo. QUANDO dovrei dichiarare le variabili membro sullo heap rispetto allo stack? La maggior parte delle risposte che ho trovato hanno affrontato altri problemi, ma voglio sapere quando è meglio usare l'heap per le variabili membro e perché è meglio ammucchiare i membri invece di impilarli.Quando e perché dichiarare variabili membro nell'heap C++

+1

* le variabili membro * si riferiscono ai membri * class * e, come tali, vanno dove si trova * l'istanza * della classe. – CapelliC

risposta

18

Ci sono due concetti importanti da cogliere prima:

  1. Si dovrebbe evitare di pensare in termini di "cumulo" e "stack". Quelli sono dettagli di implementazione del tuo compilatore/piattaforma, non della lingua. Invece, pensa in termini di durate degli oggetti: il tempo di vita dell'oggetto deve corrispondere a quello del suo "genitore", o deve sopravvivere? Se hai bisogno di quest'ultimo, dovrai utilizzare new (direttamente o indirettamente) per allocare dinamicamente un oggetto.

  2. Le variabili membro sempre hanno la stessa durata del genitore. La variabile membro può essere un puntatore e l'oggetto a cui punta potrebbe avere una durata indipendente. Ma l'oggetto puntato non è una variabile membro.

Tuttavia, non esiste una risposta generale alla domanda. In parole povere, non allocare dinamicamente a meno che non ci sia una buona ragione per farlo. Come ho accennato sopra, queste ragioni di solito corrispondono a situazioni in cui la vita ha bisogno di differire dal suo "genitore".


1. In effetti, lo standard C++ non parla in realtà di "heap" e "stack". Sono importanti da considerare quando si ottimizzano o si pensa generalmente alle prestazioni, ma sono per lo più irrilevanti dal punto di vista della funzionalità del programma.

+0

"di solito corrispondono a situazioni in cui la vita ha bisogno di differire dal suo genitore": possiamo ancora parlare di qualcosa come membro allora? –

+0

@JamesKanze: In effetti, dovrei chiarirlo. –

+1

Gli oggetti richiedono anche una durata dinamica se sono dimensionati dinamicamente o per trasmettere un oggetto a una classe base virtuale. –

1

La pila si riferisce allo call stack. Chiamate di funzioni, indirizzi di ritorno, parametri e variabili locali vengono mantenute nello stack di chiamate. Si utilizza la memoria di stack ogni volta che si passa un parametro o si crea una variabile locale. Lo stack ha solo una memoria temporanea. Una volta che la funzione corrente esce dall'ambito, non è più possibile accedere a nessuna variabile per i parametri.

L'heap è un grande pool di memoria utilizzato per l'allocazione dinamica. Quando si utilizza l'operatore new per allocare memoria, questa memoria viene assegnata dall'heap. Si desidera allocare memoria heap quando si creano oggetti che non si desidera perdere dopo che la funzione corrente è terminata (perde spazio). Gli oggetti vengono archiviati nell'heap fino a quando lo spazio non viene deallocato con delete o free().

+0

Gli oggetti richiedono anche una durata dinamica se sono dimensionati dinamicamente o per trasmettere un oggetto a una classe base virtuale. –

4

Le variabili membro sono membri della classe stessa. Non sono né su l'heap né sullo stack, o meglio, sono dove è sempre la classe .

Ci sono molto poche ragioni per aggiungere un livello di riferimento indiretto, e allocare un membro separatamente sul mucchio: polimorfismo (se il tipo dell'organo non è sempre lo stesso) è di gran lunga la più comune.

+0

Gli oggetti richiedono anche una durata dinamica se sono dimensionati dinamicamente o per trasmettere un oggetto a una classe base virtuale. –

+0

@MooingDuck Gli oggetti che sono dimensionati dinamicamente devono essere gestiti dalla loro stessa classe (ad esempio 'std :: vector'): non si assegna _them_ come membri; fai diventare il contenitore il membro. E il casting su una classe base virtuale o qualunque cosa implichi che il membro sia polimorfico, che è ciò che ho menzionato. –

+0

Ok, abbastanza giusto –

2

Per ottenere una terminologia corretta: ciò che chiamate heap e stack descrivono la durata degli oggetti.Il primo significa che la durata è dynamic, il secondo automatic e il terzo (che non si menziona) è static.

In genere è necessario il dynamic tempo di vita di un oggetto quando deve superare lo scopo in cui è stato creato. Un altro caso comune è quando si desidera condividerlo tra diversi oggetti padre. Inoltre, la vita dinamica è necessaria anche quando si lavora con un progetto che è fortemente orientato agli oggetti (utilizza un sacco di polimorfismo, non usa valori), ad es. Qt.

Un idioma che richiede vite dinamiche è l'idioma pimpl.

La maggior parte delle librerie di programmazione generica sono più focalizzate sul valore e sulla semantica del valore, quindi non si utilizzerà il collegamento dinamico tanto e le vite automatiche diventano molto più comuni.

Ci sono anche alcuni esempi in cui è richiesta l'allocazione dinamica per ragioni specifiche più attuazione:

  • oggetti di dimensioni dinamicamente (contenitori)
  • movimentazione tipi incompleti (vedi Pimpl-linguaggio)
  • facile nullability di un tipo

Tutte queste sono solo linee guida generali e devono essere decise caso per caso. In generale, preferisci oggetti automatici su quelli dinamici.

0

Considerare questo esempio:

Si implementa un elenco collegato che ha un capo membro di campo del nodo classe.
Ogni nodo ha un membro di campo next. Se questo membro del tipo Node e non Node * la dimensione di ogni nodo dipenderà dal numero dei nodi dopo di essa nella catena.

Ad esempio, se si dispone di 100 nodi nell'elenco, il proprio membro principale sarà enorme. Perché tiene il prossimo nodo dentro di sé quindi ha bisogno di avere abbastanza dimensioni per tenerlo premuto e quindi mantiene il prossimo e così via. Quindi la testa deve avere abbastanza spazio per contenere 99 nodi il prossimo 98 e così via ...

Si vuole evitare che così in questo caso è meglio avere un puntatore al nodo successivo in ciascun nodo piuttosto che il prossimo nodo stesso.

Problemi correlati