Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Gestione della memoria
Ilio Catallo – info@iliocatallo.it
Outline
¤ Tempo di vita degli oggetti
¤ Segmentazione della memoria
¤ Oggetti dinamici
¤ Strutture dinamiche
¤ Array dinam...
Tempo di vita degli oggetti
3
Oggetti
¤ Una variabile può dunque essere definita come un
oggetto con nome
¤ RICORDA: il termine oggetto può anche essere...
Oggetti
¤ Esempio: oggetto senza nome (temporaneo) di tipo int
¤ Esempio: oggetto con nome (variabile) di tipo int
std::co...
Tempo di vita di un oggetto
¤ Ogni oggetto in un programma è caratterizzato da un
proprio tempo di vita (storage duration)...
Tempo di vita di un oggetto
¤ Perchè limitare il tempo di vita degli oggetti?
¤ Per preservare spazio in memoria
¤ Esempio...
Tempo di vita di un oggetto
¤ A seconda del suo tempo di vita, un oggetto può essere
classificato come:
¤ Temporaneo
¤ Aut...
Oggetti temporanei
¤ Gli oggetti temporanei contengono risultati intermedi
ottenuti durante la valutazione di un’epression...
Oggetti temporanei
¤ L’oggetto temporaneo non ha un nome
¤ La loro creazione è invisibile all’utente
¤ Non è possibile ass...
Oggetti automatici
¤ Un oggetto automatico viene creato al momento della
sua definizione e distrutto al termine del blocco...
Oggetti automatici
¤ Attenzione a non confendere i due concetti:
¤ Il nome della variabile è locale: il nome è visibile
un...
Oggetti statici
¤ Un oggetto statico viene creato ad avvio del
programma e distrutto al termine del programma
¤ Esempi di ...
Oggetti statici
¤ Una variabile globale è una variabile il cui nome è visibile
in ogni punto del programma
¤ La variabile ...
Oggetti statici
¤ Una variabile locale static è inizializzata a zero ad
avvio del programma, e distrutta al termine
dell’a...
Oggetti statici
¤ il blocco che contiene una variabile locale static
determina la visibilità della variabile, ma non il su...
Oggetti dinamici
¤ Una volta creato, un oggetto dinamico rimane in
memoria fino a quando non viene esplicitamente
richiest...
Oggetti dinamici
int
Il programmatore
crea un oggetto
dinamico di tipo
int
5
int
L’oggetto
dinamico viene
utilizzato
5
int...
Segmentazione della memoria
19
Processo in memoria
¤ Il sistema operativo (SO) assegna ad ogni programma in
esecuzione (processo) una porzione della memo...
Processo in memoria
¤ La porzione di memoria dedicata al processo viene
chiamata lo spazio d’indirizzamento (address space...
Segmentazione
¤ Lo spazio d’indirizzamento di un processo è suddiviso in
quattro aree (segmenti):
¤ Code segment*
¤ Data s...
Segmentazione
¤ La classica rappresentazione dello spazio
d’indirizzamento è ottenuta semplicemente ruotando la
figura di ...
Segmentazione
Stack
Heap
Data
Code
1775
3472
…
memoriaassegnataal
programmainesecuzione
24
Code segment
¤ Il code segment è un’area di memoria a sola lettura che
contiene il codice che verrà eseguito
Stack
Heap
Da...
Data segment
¤ Il data segment contiene variabili globali e variabili locali
static
Stack
Heap
x: 10
ctr: 0
Code
int x = 1...
Stack segment
¤ Lo stack mantiene in memoria le variabili locali ed i
parametri in ingresso alle funzioni
int main() {
int...
Stack segment
¤ Lo stack è organizzato come una pila, ogni volta che
una funzione viene invocata, viene aggiunto un nuovo
...
Stack segment
void do_nothing2() {
int y = 13;
}
void do_nothing1() {
int x = 12;
do_nothing2();
}
int main() {
int a = 15...
Heap segment
¤ L’heap segment è l’area di memoria che contiene gli
oggetti dinamici
¤ A differenza dello stack, un nuovo o...
Oggetti dinamici
31
Creare oggetti dinamici
¤ Siamo al corrente di un solo modo per creare un oggetto
che sia successivamente modificabile:
¤ ...
Creare oggetti dinamici
¤ Assegnare un nome ad un oggetto comporta però la
definizione del suo tempo di vita
¤ Variabile l...
Creare oggetti dinamici
¤ Un oggetto dinamico deve quindi essere anonimo, in
altre parole, non deve avere un nome
Come pos...
Creare oggetti dinamici
¤ Un oggetto dinamico deve quindi essere anonimo, in
altre parole, non deve avere un nome
¤ Anche ...
Espressione new
¤ L’espressione new permette di creare oggetti dinamici
¤ Notare come:
¤ a sia una variabile locale, dunqu...
Espressione new
¤ L’espressione new permette di creare oggetti dinamici
¤ Ricorda: la variabile a non è l’oggetto dinamico...
Rappresentazione in memoria
Heap
Stack
a: int*
int
Un oggetto dinamico
non ha nome
38
Espressione new
¤ L’espressione new esegue due operazioni:
¤ Invoca l’operatore new, che alloca nell’heap il quantitativo
...
Inizializzare oggetti dinamici
¤ Gli oggetti dinamici sono inizializzati a default
¤ I tipi built-in contengono quindi un ...
Inizializzare oggetti dinamici
¤ Sono possibili diversi tipi di inizializzazione:
¤ Inizializzazione diretta: l’oggetto pu...
Modificare oggetti dinamici
¤ Per alterare oggetto dinamici si utilizza l’operatore di
indirezione *
int* a = new int;
int...
Distruggere oggetti dinamici
¤ Gli oggetti dinamici vanno esplicitamente distrutti
¤ Ogni oggetto allocato occupa parte de...
Espressione delete
¤ L’espressione delete permette di distruggere un oggetto
dinamico
¤ Dopo la delete, l’oggetto dinamico...
Espressione delete
Heap
Stack
a: int*
1
9
int
45
Espressione delete
¤ L’espressione delete esegue due operazioni:
¤ Invoca l’operatore delete, così da distrugge l’oggetto
...
Dangling pointers
¤ L’espressione delete distrugge l’oggetto dinamico
¤ Il corrispettivo puntatore non è quindi più valido...
Dangling pointers
¤ L’espressione delete distrugge l’oggetto dinamico
¤ Il puntatore è diventato un dangling pointer
¤ Dan...
Dangling pointers
¤ La soluzione è quindi rafforzare il fatto che il puntatore
non sta più puntando a nulla
¤ Regola: dopo...
Strutture dinamiche
50
Strutture
¤ Le strutture generalizzano il concetto di array:
¤ Un array è una sequenza di elementi dello stesso tipo
¤ Una...
Strutture
¤ Address è un tipo composto e definito dall’utente
¤ Una volta che il tipo Address è stato definito, è possibil...
Inizializzare una struttura
¤ Dal C++11, è possibile inizializzare oggetti di tipo struttura
mediante una lista di inizial...
Member access operator
¤ I membri di una struttura sono accessibili mediante
l’operatore . (member access operator)
54
pol...
Strutture dinamiche
¤ È possibile dichiarare strutture dinamiche mediante
l’espressione new
¤ L’espressione new restituisc...
Strutture dinamiche
¤ Esempio: la struttura polico_address è inizializzata a
default
56
Address* polico_address = new Addr...
Rappresentazione in memoria
57
Heap
Stack
polico_address: Address*
Un struttura dinamica
non ha nome street:
number:
town:...
Inizializzare una struttura dinamica
¤ Dal C++11, una struttura dinamica può essere inizializzata
con una lista di inizial...
Accedere a membri di
una struttura dinamica
¤ Per accedere alla struttura dinamica è necessario:
¤ Accedere alla struttura...
Accedere a membri di
una struttura dinamica
¤ Per accessi a membri di una struttura mediante
puntatore è disponibile una v...
Distruggere una struttura dinamica
¤ Una struttura dinamica si distrugge mediante l’utilizzo
della espressione delete
61
d...
Array dinamici
Creare array dinamici
¤ Un array dinamico può essere creato mediante
l’espressione new[]
¤ L’espressione new restituisce l...
Creare array dinamici
Heap
Stack
numbers: int*
int[5]
Un array dinamico non
ha nome
(array anonimo)
64
Inizializzare un array dinamico
¤ Dall C++11, un array dinamico può essere inizializzato in
in modo simile ad un comune ar...
Accedere ad un array dinamico
¤ L’accesso ad un array dinamico avviene secondo le
stesse modalità di un comune array
¤ Inf...
Distruggere un array dinamico
¤ Il programmatore è responsabile della distruzione di array
dinamici non più necessari
¤ L’...
Distruggere un array dinamico
¤ L’uso delle [] è cruciale
¤ È l’unico modo per chiedere al compilatore di distruggere
un a...
Array di dimensioni variabili
Dimensione di un array
¤ La dimensione di un array automatico deve essere nota
a tempo di compilazione (compile time)
¤ Ta...
Dimensione di un array
vs stack
¤ Invocare una funzione significa impilare un nuovo frame
nello stack segment
void do_noth...
Frame pointer e stack pointer
¤ Durante l’esecuzione di una funzione, possiamo
identificare due indirizzi importanti in me...
Frame pointer e stack pointer
¤ Se supponiamo che do_nothing() sia in esecuzione, si
ha che:
a: 12
x: 2
y[0]: 5
y[1]: 4
c:...
Frame pointer e stack pointer
¤ Gli indirizzi delle variabili locali della funzione in
esecuzione sono deducibili a partir...
Frame pointer e stack pointer
¤ Se supponiamo che un int occupi 2 byte, e un char 1
byte
a: 12
x: 2
y[0]: 5
y[1]: 4
c: 3
s...
Dimensione di un array
¤ Se richiediamo che le variabili abbiano dimensioni note a
priori tutti gli spiazzamenti sono calc...
Array di dimensioni variabili
¤ Non possiamo usare normali array, perchè verrebbero
allocati nello stack, totalmente gesti...
Array di dimensioni variabili
¤ Al momento della creazione di un array dinamico, la
dimensione può essere una qualsiasi es...
Array dinamici multidimensionali
79
Array dinamici multidim.
¤ È possibile creare un array dinamico multidimensionale
attraverso l’espressione new[]
¤ L’espre...
Array dinamici multidim.
Heap
Stack
matrix: int(*)[3]
int[3][3
]
!
81
Alias per i sotto-array
¤ È possibile aumentare la leggibilità del codice definendo
un alias per il tipo “riga della matri...
Nascondere il tipo dei sotto-array
¤ Dal C++11, è possibile far sì che sia il compilatore a
dedurre il tipo dato di una va...
Inizializzare array dinamici
multidimensionali
¤ Dal C++11, è possibile inizializzare un array dinamico
multidim. in manie...
Distruggere array dinamici
multidimensionali
¤ Così come per i normali array dinamici, l’espressione
delete[] consente di ...
Array dinamici multidim.
di dimensione variabile
¤ Tutte le dimensioni dell’array, con la sola eccezione della
prima, devo...
Bibliografia
87
Bibliografia
¤ S. B. Lippman, J. Lajoie, B. E. Moo, C++ Primer (5th Ed.)
¤ B. Stroustrup, The C++ Programming Language (4t...
Bibliografia
¤ C++ Reference, Zero initialization
http://en.cppreference.com/w/cpp/language/zero_initializ
ation
¤ C++ Ref...
Bibliografia
¤ Wikipedia, Data Segment
http://en.wikipedia.org/wiki/Data_segment
¤ University of Alberta, Understanding me...
Bibliografia
¤ Stackoverflow FAQ, “How do I use arrays in C++?”
http://stackoverflow.com/questions/4810664/how-do-i-
use-a...
Upcoming SlideShare
Loading in …5
×

Gestione della memoria in C++

1,964 views

Published on

Introduzione al concetto di oggetto nel modello della memoria del C++ e ai suoi possibile tempi di vita (temporaneo, automatico, dinamico, ...). Relazione tra il tempo di vita e la visibilità (scope) di un oggetto. Gestione degli oggetti dinamici per tipi primitivi, strutture e array mediante l'utilizzo di puntatori (raw pointers).

Published in: Education
  • Be the first to comment

Gestione della memoria in C++

  1. 1. Gestione della memoria Ilio Catallo – info@iliocatallo.it
  2. 2. Outline ¤ Tempo di vita degli oggetti ¤ Segmentazione della memoria ¤ Oggetti dinamici ¤ Strutture dinamiche ¤ Array dinamici ¤ Array monodimensionali ¤ Array multidimensionali 2
  3. 3. Tempo di vita degli oggetti 3
  4. 4. Oggetti ¤ Una variabile può dunque essere definita come un oggetto con nome ¤ RICORDA: il termine oggetto può anche essere usato come sinonimo di istanza di una classe ¤ Le due definizioni non sono equivalenti Un oggetto è una regione di memoria di un determinato tipo dato 4
  5. 5. Oggetti ¤ Esempio: oggetto senza nome (temporaneo) di tipo int ¤ Esempio: oggetto con nome (variabile) di tipo int std::cout << (5+3)*3 << std::endl; int result = (5+3)*3; // ‘result’ is the name of // an object of type int std::cout << result << std::endl; 5
  6. 6. Tempo di vita di un oggetto ¤ Ogni oggetto in un programma è caratterizzato da un proprio tempo di vita (storage duration) ¤ Tempo di vita: l’intervallo di tempo che intercorre tra la creazione dell’oggetto e la sua distruzione 6
  7. 7. Tempo di vita di un oggetto ¤ Perchè limitare il tempo di vita degli oggetti? ¤ Per preservare spazio in memoria ¤ Esempio: se una funzione non è in esecuzione, non c’è motivo di mantenere in memoria le corrispettive variabili locali 7
  8. 8. Tempo di vita di un oggetto ¤ A seconda del suo tempo di vita, un oggetto può essere classificato come: ¤ Temporaneo ¤ Automatico ¤ Statico ¤ Dinamico ¤ Thread-local 8
  9. 9. Oggetti temporanei ¤ Gli oggetti temporanei contengono risultati intermedi ottenuti durante la valutazione di un’epressione ¤ Esempio: Il risultato di y*z deve essere salvato da qualche parte prima di poter essere aggiunto a x int v = x + y*z; 9
  10. 10. Oggetti temporanei ¤ L’oggetto temporaneo non ha un nome ¤ La loro creazione è invisibile all’utente ¤ Non è possibile assegnargli un valore ¤ L’oggetto viene distrutto al termine della full-expression che lo contiene ¤ Full-expression: un’espressione che non è contenuta in un’espressione più grande int v = x + y*z; 10
  11. 11. Oggetti automatici ¤ Un oggetto automatico viene creato al momento della sua definizione e distrutto al termine del blocco che lo contiene ¤ Esempio: la variabile locale x viene distrutta al termine del blocco, ed è quindi un oggetto automatico void do_nothing() { int x = 12; } 11
  12. 12. Oggetti automatici ¤ Attenzione a non confendere i due concetti: ¤ Il nome della variabile è locale: il nome è visibile unicamente all’interno del blocco ¤ L’oggetto è automatico: la variabile verrà distrutta al termine del blocco una variabile locale è un oggetto automatico 12
  13. 13. Oggetti statici ¤ Un oggetto statico viene creato ad avvio del programma e distrutto al termine del programma ¤ Esempi di oggetti statici: ¤ Variabili globali ¤ Variabili locali dichiarate come static 13
  14. 14. Oggetti statici ¤ Una variabile globale è una variabile il cui nome è visibile in ogni punto del programma ¤ La variabile globale x è un oggetto statico, la sua vita termina al termine del programma int x = 10; int main() { x = 5; // 'x' is a global variable std::cout << x << std::endl; } 14
  15. 15. Oggetti statici ¤ Una variabile locale static è inizializzata a zero ad avvio del programma, e distrutta al termine dell’applicativo ¤ Esempio: la variabile ctr viene incrementata ad ogni chiamata di count_calls() size_t count_calls() { static size_t ctr; return ++ctr; } 15
  16. 16. Oggetti statici ¤ il blocco che contiene una variabile locale static determina la visibilità della variabile, ma non il suo tempo di vita ¤ Il nome della variabile è visibile solo all’interno della funzione, ma… ¤ La variabile viene distrutta al termine del programma, non al termine della funzione size_t count_calls() { static size_t ctr; return ++ctr; } 16
  17. 17. Oggetti dinamici ¤ Una volta creato, un oggetto dinamico rimane in memoria fino a quando non viene esplicitamente richiesta la sua distruzione ¤ Il tempo di vita di un oggetto dinamico è gestito dal programmatore, che decide: ¤ Quando creare l’oggetto dinamico ¤ Quando distruggere l’oggetto 17
  18. 18. Oggetti dinamici int Il programmatore crea un oggetto dinamico di tipo int 5 int L’oggetto dinamico viene utilizzato 5 int Il programmatore distrugge l’oggetto quando non più necessario 18
  19. 19. Segmentazione della memoria 19
  20. 20. Processo in memoria ¤ Il sistema operativo (SO) assegna ad ogni programma in esecuzione (processo) una porzione della memoria disponibile ¤ Tale memoria permette l’effettiva esecuzione del programma ¤ Esempio: una parte viene adoperata per mantenere in memoria il valore delle variabili 20
  21. 21. Processo in memoria ¤ La porzione di memoria dedicata al processo viene chiamata lo spazio d’indirizzamento (address space) del processo memoria assegnata al programma in esecuzione 1775 3472… 21
  22. 22. Segmentazione ¤ Lo spazio d’indirizzamento di un processo è suddiviso in quattro aree (segmenti): ¤ Code segment* ¤ Data segment ¤ Heap segment ¤ Stack segment ¤ Ogni segmento viene utilizzato per uno scopo diverso *anche detto text segment 22
  23. 23. Segmentazione ¤ La classica rappresentazione dello spazio d’indirizzamento è ottenuta semplicemente ruotando la figura di 90° memoria assegnata al programma in esecuzione Stack 1775 3472… HeapDataCode 23
  24. 24. Segmentazione Stack Heap Data Code 1775 3472 … memoriaassegnataal programmainesecuzione 24
  25. 25. Code segment ¤ Il code segment è un’area di memoria a sola lettura che contiene il codice che verrà eseguito Stack Heap Data movl $12, -12(%rbp) movl $13, -16(%rbp) movl -12(%rbp), %eax int main() { int a = 12, b = 13; int c = a + b; } 25
  26. 26. Data segment ¤ Il data segment contiene variabili globali e variabili locali static Stack Heap x: 10 ctr: 0 Code int x = 10; size_t count_calls() { static size_t ctr; return ++ctr; } int main() { count_calls(); return 0; } 26
  27. 27. Stack segment ¤ Lo stack mantiene in memoria le variabili locali ed i parametri in ingresso alle funzioni int main() { int a = 15, b = 10; return 0; } a: 15 b: 10 spazio rimanente nello stack Heap Data Code 27
  28. 28. Stack segment ¤ Lo stack è organizzato come una pila, ogni volta che una funzione viene invocata, viene aggiunto un nuovo strato ¤ Il nuovo strato (frame) contiene le variabili locali ed i parametri in ingresso della funzione appena invocata* ¤ Quando una funzione termina, il corrispettivo frame viene rimosso dalla pila ¤ Le variabili locali vengono automaticamente distrutte * il frame contiene anche informazioni che permettono, una volta termina una funzione, che il controllo ritorni alla funzione chiamante 28
  29. 29. Stack segment void do_nothing2() { int y = 13; } void do_nothing1() { int x = 12; do_nothing2(); } int main() { int a = 15, b = 10; do_nothing1(); return 0; } a: 15 b: 10 x: 12 y:13 spazio rimanente nello stack main() do_nothing1() do_nothing2() Frame 1 Frame 2 Frame 3 29
  30. 30. Heap segment ¤ L’heap segment è l’area di memoria che contiene gli oggetti dinamici ¤ A differenza dello stack, un nuovo oggetto può occupare una posizione casuale all’interno dell’heap ¤ Conseguenza: non esiste nessun meccanismo che automaticamente elimini gli oggetti non più utilizzati Heap Occupato Libero 30
  31. 31. Oggetti dinamici 31
  32. 32. Creare oggetti dinamici ¤ Siamo al corrente di un solo modo per creare un oggetto che sia successivamente modificabile: ¤ Assegnargli un nome, in altre parole definire una variabile Come possiamo creare un oggetto dinamico? 32
  33. 33. Creare oggetti dinamici ¤ Assegnare un nome ad un oggetto comporta però la definizione del suo tempo di vita ¤ Variabile locale? oggetto automatico ¤ Variabile locale static? oggetto statico ¤ variabile globale? oggetto statico Come possiamo creare un oggetto dinamico? 33
  34. 34. Creare oggetti dinamici ¤ Un oggetto dinamico deve quindi essere anonimo, in altre parole, non deve avere un nome Come possiamo manipolare un oggetto senza nome? 34
  35. 35. Creare oggetti dinamici ¤ Un oggetto dinamico deve quindi essere anonimo, in altre parole, non deve avere un nome ¤ Anche se senza nome, l’oggetto dinamico deve avere un indirizzo ¤ IDEA: usare un puntatore per contenere l’indirizzo dell’oggetto dinamico Come possiamo manipolare un oggetto senza nome? 35
  36. 36. Espressione new ¤ L’espressione new permette di creare oggetti dinamici ¤ Notare come: ¤ a sia una variabile locale, dunque un oggetto automatico ¤ l’oggetto int anonimo sia invece un oggetto dinamico int* a = new int; // 'a' is pointing to an unnamed, // dynamic object of type int 36
  37. 37. Espressione new ¤ L’espressione new permette di creare oggetti dinamici ¤ Ricorda: la variabile a non è l’oggetto dinamico, è un puntatore all’oggetto dinamico int* a = new int; // 'a' is pointing to an unnamed, // dynamic object of type int 37
  38. 38. Rappresentazione in memoria Heap Stack a: int* int Un oggetto dinamico non ha nome 38
  39. 39. Espressione new ¤ L’espressione new esegue due operazioni: ¤ Invoca l’operatore new, che alloca nell’heap il quantitativo di memoria necessaria ¤ Costruisce l’oggetto nell’area di memoria designata ¤ L’espressione new restituisce l’indirizzo dell’oggetto dinamico int* a = new int; 39
  40. 40. Inizializzare oggetti dinamici ¤ Gli oggetti dinamici sono inizializzati a default ¤ I tipi built-in contengono quindi un valore non noto ¤ Istanze di una classe vengono inizializzati attraverso il costruttore di default ¤ Come per gli oggetti automatici, è quindi buona norma inizializzare gli oggetti dinamici con valori sensati 40
  41. 41. Inizializzare oggetti dinamici ¤ Sono possibili diversi tipi di inizializzazione: ¤ Inizializzazione diretta: l’oggetto puntato da d vale 12 ¤ Inizializzazione per copia: l’oggetto puntato da c vale 20 ¤ Inizializzazione per valore: l’oggetto puntato da e vale 0 int b = 20; int* d = new int(12); // direct initialization int* c = new int(b); // copy initialization int* e = new int(); // value initialization 41
  42. 42. Modificare oggetti dinamici ¤ Per alterare oggetto dinamici si utilizza l’operatore di indirezione * int* a = new int; int b = 12; *a = b + 7; std::cout << "the value pointed to by a is ” << *a << std::endl; } 42
  43. 43. Distruggere oggetti dinamici ¤ Gli oggetti dinamici vanno esplicitamente distrutti ¤ Ogni oggetto allocato occupa parte della memoria disponibile nell’heap ¤ La memoria non è illimitata ¤ È tecnicamente possibile saturare tutto lo spazio a disposizione 43
  44. 44. Espressione delete ¤ L’espressione delete permette di distruggere un oggetto dinamico ¤ Dopo la delete, l’oggetto dinamico puntato da a non esiste più int* a = new int; int b = 12; *a = b + 7; delete a; 44
  45. 45. Espressione delete Heap Stack a: int* 1 9 int 45
  46. 46. Espressione delete ¤ L’espressione delete esegue due operazioni: ¤ Invoca l’operatore delete, così da distrugge l’oggetto ¤ Dealloca la memoria precedentemente allocata, rendendola così nuovamente disponibile delete a; 46
  47. 47. Dangling pointers ¤ L’espressione delete distrugge l’oggetto dinamico ¤ Il corrispettivo puntatore non è quindi più valido ¤ Infatti, l’oggetto puntato non esiste più ¤ Il puntatore continua però a contenere l’indirizzo di dove una volta si trovava l’oggetto dinamico 47
  48. 48. Dangling pointers ¤ L’espressione delete distrugge l’oggetto dinamico ¤ Il puntatore è diventato un dangling pointer ¤ Dangling pointer: puntatore che punta ad un area di memoria precedentemente occupata da un oggetto non più esistente 48
  49. 49. Dangling pointers ¤ La soluzione è quindi rafforzare il fatto che il puntatore non sta più puntando a nulla ¤ Regola: dopo la distruzione di un oggetto dinamico, il corrispettivo puntatore deve essere posto a nullptr (o NULL) delete a; a = nullptr; 49
  50. 50. Strutture dinamiche 50
  51. 51. Strutture ¤ Le strutture generalizzano il concetto di array: ¤ Un array è una sequenza di elementi dello stesso tipo ¤ Una struttura è un sequenza di elementi di tipo diversi 51 Una struttura è una sequenza di elementi (membri) di tipo arbitrario
  52. 52. Strutture ¤ Address è un tipo composto e definito dall’utente ¤ Una volta che il tipo Address è stato definito, è possibile dichiarare variabili di tipo Address: 52 struct Address { std::string street; int number; std::string town; }; Address polimi_address;
  53. 53. Inizializzare una struttura ¤ Dal C++11, è possibile inizializzare oggetti di tipo struttura mediante una lista di inizializzazione* 53 * prima del C++11, ciò era possibile unicamente nel caso in cui la struttura fosse stata anche un aggregato Address polimi_address = {"Piazza Leonardo Da Vinci", 32, "Milan"};
  54. 54. Member access operator ¤ I membri di una struttura sono accessibili mediante l’operatore . (member access operator) 54 polimi_address.street = "Piazza Leonardo Da Vinci"; polimi_address.number = 32; polimi_address.town = "Milan”;
  55. 55. Strutture dinamiche ¤ È possibile dichiarare strutture dinamiche mediante l’espressione new ¤ L’espressione new restituisce l’indirizzo della struttura dinamica allocata nell’heap 55
  56. 56. Strutture dinamiche ¤ Esempio: la struttura polico_address è inizializzata a default 56 Address* polico_address = new Address; // default // initialization
  57. 57. Rappresentazione in memoria 57 Heap Stack polico_address: Address* Un struttura dinamica non ha nome street: number: town: Address
  58. 58. Inizializzare una struttura dinamica ¤ Dal C++11, una struttura dinamica può essere inizializzata con una lista di inizializzazione* 58 Address* polico_address = new Address{“Via Valleggio", 11, ”Como"};// uniform // initialization
  59. 59. Accedere a membri di una struttura dinamica ¤ Per accedere alla struttura dinamica è necessario: ¤ Accedere alla struttura mediante l’operatore * ¤ Accedere a un particolare membro mediante l’operatore . 59 (*polico_address).street = "Via Valleggio”; Mediante indirezione recuperiamo la struttura Mediante l’operatore di accesso alteriamo un particolare membro della struttura
  60. 60. Accedere a membri di una struttura dinamica ¤ Per accessi a membri di una struttura mediante puntatore è disponibile una variante del member access operator ¤ L’operatore -> è talvolta indicato come pointer-to-member operator 60 polico_address->street = "Via Valleggio”;
  61. 61. Distruggere una struttura dinamica ¤ Una struttura dinamica si distrugge mediante l’utilizzo della espressione delete 61 delete polico_address;
  62. 62. Array dinamici
  63. 63. Creare array dinamici ¤ Un array dinamico può essere creato mediante l’espressione new[] ¤ L’espressione new restituisce l’indirizzo del primo elemento dell’array (non avviene alcun decadimento) ¤ Nell’esempio, tale indirizzo viene salvato in un puntatore di nome numbers int* numbers = new int[5]; // dynamic (hence, unnamed) array // of 5 elements of type int 63
  64. 64. Creare array dinamici Heap Stack numbers: int* int[5] Un array dinamico non ha nome (array anonimo) 64
  65. 65. Inizializzare un array dinamico ¤ Dall C++11, un array dinamico può essere inizializzato in in modo simile ad un comune array*: ¤ Tale modalità di inizializzazione si chiama inizializzazione uniforme (uniform initialization) int* numbers = new int[5]{1, 7, 13, 5, 9}; 65 *Differentemente dai comuni array è però sempre necessario specificare la dimensione
  66. 66. Accedere ad un array dinamico ¤ L’accesso ad un array dinamico avviene secondo le stesse modalità di un comune array ¤ Infatti, come sappiamo l’operatore [] è un operatore definito sui puntatori int* numbers = new int[5]{1, 7, 13, 5, 9}; numbers[2] = 20; // implemented as *(numbers + 2) = 20 66
  67. 67. Distruggere un array dinamico ¤ Il programmatore è responsabile della distruzione di array dinamici non più necessari ¤ L’espressione delete[] distrugge un array dinamico delete[] numbers; 67
  68. 68. Distruggere un array dinamico ¤ L’uso delle [] è cruciale ¤ È l’unico modo per chiedere al compilatore di distruggere un array di oggetti, piuttosto che un singolo oggetto ¤ Se non usato, si incappa in un undefined behavior delete[] numbers; 68
  69. 69. Array di dimensioni variabili
  70. 70. Dimensione di un array ¤ La dimensione di un array automatico deve essere nota a tempo di compilazione (compile time) ¤ Tale imposizione facilita la gestione della stack segment constexpr size_t DIM = 5; int numbers[DIM]; 70
  71. 71. Dimensione di un array vs stack ¤ Invocare una funzione significa impilare un nuovo frame nello stack segment void do_nothing() { int x = 2; char y[2] ={5, 4}; int c = 3; } int main() { int a = 12; do_nothing(); return 0; } a: 12 x: 2 y[0]: 5 y[1]: 4 c: 3 spazio rimamente nello stack main() do_nothing() 71
  72. 72. Frame pointer e stack pointer ¤ Durante l’esecuzione di una funzione, possiamo identificare due indirizzi importanti in memoria ¤ Stack pointer: l’indirizzo dell’ultima cella di memoria valida nello stack ¤ Frame pointer: l’indirizzo della prima cella di memoria appartenente al frame attualmente in esecuzione 72
  73. 73. Frame pointer e stack pointer ¤ Se supponiamo che do_nothing() sia in esecuzione, si ha che: a: 12 x: 2 y[0]: 5 y[1]: 4 c: 3 spazio rimamente nello stack do_nothing() stack pointer frame pointer main() 73
  74. 74. Frame pointer e stack pointer ¤ Gli indirizzi delle variabili locali della funzione in esecuzione sono deducibili a partire dall’indirizzo contenuto nel frame pointer ¤ Dove lo spiazzamento è misurato in byte indirizzo var. locale = frame pointer + spiazzamento 74
  75. 75. Frame pointer e stack pointer ¤ Se supponiamo che un int occupi 2 byte, e un char 1 byte a: 12 x: 2 y[0]: 5 y[1]: 4 c: 3 spazio rimamente nello stack stack pointer frame pointer frame pointer + 0 frame pointer + 2 byte frame pointer + 3 byte frame pointer + 4 byte 75
  76. 76. Dimensione di un array ¤ Se richiediamo che le variabili abbiano dimensioni note a priori tutti gli spiazzamenti sono calcolabili a compile-time ¤ Conseguenza: è possibile conoscere a tempo di compilazione la dimensione del frame di una funzione ¤ Questo comporta: ¤ Codice più veloce ¤ Maggiore semplicità nella scrittura dei compilatori 76
  77. 77. Array di dimensioni variabili ¤ Non possiamo usare normali array, perchè verrebbero allocati nello stack, totalmente gestito dal compilatore ¤ Al contrario, l’heap è una porzione di memoria totalmente a disposizione del programmatore ¤ IDEA: memorizzare l’array di dimensioni variabili all’interno dell’heap segment Come definire un array la cui dimensione venga specificata a tempo d’esecuzione (run time)? 77
  78. 78. Array di dimensioni variabili ¤ Al momento della creazione di un array dinamico, la dimensione può essere una qualsiasi espressione ¤ Non è richiesto che l’espressione sia costante ¤ Nell’esempio, dim non è una quantità costante, ma può comunque essere usata per creare un array dinamico size_t dim = 5; int* numbers = new int[dim]; 78
  79. 79. Array dinamici multidimensionali 79
  80. 80. Array dinamici multidim. ¤ È possibile creare un array dinamico multidimensionale attraverso l’espressione new[] ¤ L’espressione new[] restituisce l’indirizzo del primo elemento dell’array multidim. ¤ Gli elementi di un un array multidim. sono a loro volta array ¤ Un puntatore al primo elemento è un puntatore ad array int (*matrix)[3] = new int[3][3]; 80
  81. 81. Array dinamici multidim. Heap Stack matrix: int(*)[3] int[3][3 ] ! 81
  82. 82. Alias per i sotto-array ¤ È possibile aumentare la leggibilità del codice definendo un alias per il tipo “riga della matrice” ¤ La scrittura evidenzia come la new[] restituisca un puntatore alla prima riga della matrice using matrix_row = int[3]; matrix_row* matrix = new int[3][3]; 82
  83. 83. Nascondere il tipo dei sotto-array ¤ Dal C++11, è possibile far sì che sia il compilatore a dedurre il tipo dato di una variabile definendo la variabile come auto ¤ Tale funzionalità può essere usata per aumentare la leggibilità auto matrix = new int[3][3]; 83
  84. 84. Inizializzare array dinamici multidimensionali ¤ Dal C++11, è possibile inizializzare un array dinamico multidim. in maniera simile ad un normale array multidim. auto matrix = new int[3][3]{{1, 7, 14}, {8, 16, 12}, {27, 32, 5}}; 84
  85. 85. Distruggere array dinamici multidimensionali ¤ Così come per i normali array dinamici, l’espressione delete[] consente di distruggere array multidimensionali delete[] matrix; 85
  86. 86. Array dinamici multidim. di dimensione variabile ¤ Tutte le dimensioni dell’array, con la sola eccezione della prima, devono essere note a tempo di compilazione ¤ matrix è un array dinamico di N elementi di tipo int[3] ¤ Essendo dinamico, N può essere noto a run time ¤ Il tipo dell’elemento (int[3]) deve però essere noto a compile time size_t N = 3; auto matrix = new int[N][3] // OK auto matrix2 = new int[3][N] // ERROR! 86
  87. 87. Bibliografia 87
  88. 88. Bibliografia ¤ S. B. Lippman, J. Lajoie, B. E. Moo, C++ Primer (5th Ed.) ¤ B. Stroustrup, The C++ Programming Language (4th Ed.) ¤ S. Meyers, Effective C++ (2nd Ed.) ¤ R. Lafore, Object Oriented Programming in C++ (4th Ed.) 88
  89. 89. Bibliografia ¤ C++ Reference, Zero initialization http://en.cppreference.com/w/cpp/language/zero_initializ ation ¤ C++ Reference, Value initialization http://en.cppreference.com/w/cpp/language/value_initiali zation ¤ C++ Reference, new expressionhttp://en.cppreference.com/w/cpp/language/n ew ¤ C++ Reference, delete expression http://en.cppreference.com/w/cpp/language/delete 89
  90. 90. Bibliografia ¤ Wikipedia, Data Segment http://en.wikipedia.org/wiki/Data_segment ¤ University of Alberta, Understanding memory http://www.ualberta.ca/CNS/RESEARCH/LinuxClusters/m em.html ¤ G. Duarte, Anatomy of a program in memory http://duartes.org/gustavo/blog/post/anatomy-of-a- program-in-memory 90
  91. 91. Bibliografia ¤ Stackoverflow FAQ, “How do I use arrays in C++?” http://stackoverflow.com/questions/4810664/how-do-i- use-arrays-in-c ¤ Stackoverflow FAQ, “What are Aggregates and PODs and how/why are they special?” http://stackoverflow.com/q/4178175/1849221 91

×