Sommario:
- Ambito limitato in C ++
- Esaminare il problema dell'ambito in C ++
- Fornire una soluzione utilizzando l'heap in C ++
Video: Método Heap Sort , Algoritmo de Ordenamiento, Programación Avanzada 2024
L'heap è un blocco di memoria amorfo a cui il programma C ++ può accedere se necessario. Scopri perché esiste e come usarlo.
Così come è possibile passare un puntatore a una funzione, è possibile che una funzione restituisca un puntatore. Una funzione che restituisce l'indirizzo di una doppia viene dichiarata come segue:
double * fn (void);
Tuttavia, si deve fare molta attenzione quando si restituisce un puntatore. Per capire i pericoli, devi sapere qualcosa sull'ambito della variabile.
Ambito limitato in C ++
L'ambito è l'intervallo su cui è definita una variabile. Si consideri il seguente frammento di codice:
// la seguente variabile è accessibile a // tutte le funzioni e definita fintanto che // programma è in esecuzione (ambito globale) int intGlobal; // la seguente variabile intChild è accessibile // solo alla funzione ed è definita solo // fintanto che C ++ sta eseguendo child () o una funzione // quale child () chiama (scope della funzione) void child (void) {int intChild;} // la seguente variabile intParent ha la funzione // scope void parent (void) {int intParent = 0; bambino(); int intLater = 0; intParent = intLater;} int main (int nArgs, char * pArgs []) {parent ();}
Questo frammento di programma inizia con la dichiarazione di una variabile intGlobal. Questa variabile esiste dal momento in cui il programma inizia l'esecuzione fino alla sua conclusione. Si dice che intGlobal "ha portata del programma. "Si dice anche che la variabile" entra nell'ambito "anche prima che venga chiamata la funzione main ().
La funzione main () richiama immediatamente parent (). La prima cosa che il processore vede in parent () è la dichiarazione di intParent. A quel punto, intParent entra nel campo di applicazione, ovvero intParent è definito e disponibile per il resto della funzione parent ().
La seconda istruzione in parent () è la chiamata a child (). Ancora una volta, la funzione child () dichiara una variabile locale, questa volta intChild. L'ambito della variabile intChild è limitato alla funzione child (). Tecnicamente, intParent non è definito nell'ambito di child () perché child () non ha accesso a intParent; tuttavia, la variabile intParent continua ad esistere mentre child () è in esecuzione.
Quando termina child (), la variabile intChild esce dallo scope. IntChild non solo non è più accessibile, non esiste più. (La memoria occupata da intChild viene restituita al pool generale per essere utilizzata per altre cose.)
Mentre genitore () continua ad essere eseguito, la variabile intLater entra nell'ambito della dichiarazione. Al punto che parent () torna a main (), sia intParent che intLater escono dall'ambito.
Poiché intGlobal è dichiarato globalmente in questo esempio, è disponibile per tutte e tre le funzioni e rimane disponibile per la vita del programma.
Esaminare il problema dell'ambito in C ++
Il seguente segmento di codice compila senza errori ma non funziona (non lo odi?):
double * child (void) {double dLocalVariable; return & dLocalVariable;} void parent (void) {double * pdLocal; pdLocal = child (); * pdLocal = 1. 0;}
Il problema con questa funzione è che dLocalVariable è definita solo nell'ambito della funzione child (). Quindi, quando l'indirizzo di memoria di dLocalVariable viene restituito da child (), fa riferimento a una variabile che non esiste più. La memoria che dLocalVariable precedentemente occupata è probabilmente utilizzata per qualcos'altro.
Questo errore è molto comune perché può insinuarsi in vari modi. Sfortunatamente, questo errore non causa l'arresto istantaneo del programma. In effetti, il programma può funzionare bene la maggior parte del tempo - cioè, il programma continua a funzionare finché la memoria precedentemente occupata da dLocalVariable non viene riutilizzata immediatamente. Tali problemi intermittenti sono i più difficili da risolvere.
Fornire una soluzione utilizzando l'heap in C ++
Il problema dell'ambito è stato generato poiché C ++ ha recuperato la memoria definita localmente prima che il programmatore fosse pronto. Ciò che è necessario è un blocco di memoria controllato dal programmatore. Può allocare il ricordo e rimetterlo quando vuole - non perché C ++ pensa che sia una buona idea. Un tale blocco di memoria è chiamato heap.
La memoria heap viene allocata utilizzando la nuova parola chiave seguita dal tipo di oggetto da allocare. Il nuovo comando rompe un mucchio di memoria dall'heap abbastanza grande da contenere il tipo specificato di oggetto e restituisce il suo indirizzo. Ad esempio, il seguente alloca una doppia variabile dall'heap:
double * child (void) {double * pdLocalVariable = new double; return pdLocalVariable;}
Questa funzione ora funziona correttamente. Sebbene la variabile pdLocalVariable vada fuori campo quando la funzione child () restituisce, la memoria a cui fa riferimento pdLocalVariable non lo fa. Una posizione di memoria restituita da new non esce dall'ambito finché non viene esplicitamente restituita all'heap utilizzando la parola chiave delete, che è specificatamente progettata per tale scopo:
void parent (void) {// child () restituisce l'indirizzo di un blocco // di memoria heap double * pdMyDouble = child (); // memorizza un valore lì * pdMyDouble = 1. 1; // … // ora restituisce la memoria allo heap delete pdMyDouble; pdMyDouble = 0; // …}
Qui il puntatore restituito da child () viene utilizzato per memorizzare un valore double. Al termine della funzione con la posizione di memoria, viene restituito all'heap. La funzione parent () imposta il puntatore su 0 dopo che è stata restituita la memoria dell'heap - questo non è un requisito, ma è un'ottima idea.
Se il programmatore tenta erroneamente di memorizzare qualcosa in * pdMyDouble dopo l'eliminazione, il programma si bloccherà immediatamente con un messaggio di errore significativo.
Puoi usare new per allocare array anche dall'heap, ma devi restituire un array usando la parola chiave delete []:
int * nArray = new int [10]; nArray [0] = 0; delete [] nArray;
Technically new int [10] richiama il nuovo [] operatore ma funziona come nuovo.