Gestione della memoria
Ilio Catallo – Politecnico di Milano
ilio.catallo@polimi.it
Outline
¤  Tempo di vita degli oggetti
¤  Segmentazione della memoria
¤  Oggetti dinamici
¤  Strutture dinamiche
¤  A...
Tempo di vita degli oggetti
3
Oggetti
¤  Una variabile può dunque essere definita come un
oggetto con nome
¤  RICORDA: il termine oggetto può anche es...
Oggetti
¤  Esempio: oggetto senza nome (temporaneo) di tipo int
¤  Esempio: oggetto con nome (variabile) di tipo int
std...
Tempo di vita di un oggetto
¤  Ogni oggetto in un programma è caratterizzato da un
proprio tempo di vita (storage duratio...
Tempo di vita di un oggetto
¤  Perchè limitare il tempo di vita degli oggetti?
¤  Per preservare spazio in memoria
¤  E...
Tempo di vita di un oggetto
¤  A seconda del suo tempo di vita, un oggetto può essere
classificato come:
¤  Temporaneo
¤...
Oggetti temporanei
¤  Gli oggetti temporanei contengono risultati intermedi
ottenuti durante la valutazione di un’epressi...
Oggetti temporanei
¤  L’oggetto temporaneo non ha un nome
¤  La loro creazione è invisibile all’utente
¤  Non è possibi...
Oggetti automatici
¤  Un oggetto automatico viene creato al momento della
sua definizione e distrutto al termine del bloc...
Oggetti automatici
¤  Attenzione a non confendere i due concetti:
¤  Il nome della variabile è locale: il nome è visibil...
Oggetti statici
¤  Un oggetto statico viene creato ad avvio del
programma e distrutto al termine del programma
¤  Esempi...
Oggetti statici
¤  Una variabile globale è una variabile il cui nome è visibile
in ogni punto del programma
¤  La variab...
Oggetti statici
¤  Una variabile locale static è inizializzata a zero ad
avvio del programma, e distrutta al termine
dell...
Oggetti statici
¤  il blocco che contiene una variabile locale static
determina la visibilità della variabile, ma non il ...
Oggetti dinamici
¤  Una volta creato, un oggetto dinamico rimane in
memoria fino a quando non viene esplicitamente
richie...
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 me...
Processo in memoria
¤  La porzione di memoria dedicata al processo viene
chiamata lo spazio d’indirizzamento (address spa...
Segmentazione
¤  Lo spazio d’indirizzamento di un processo è suddiviso in
quattro aree (segmenti):
¤  Code segment*
¤  ...
Segmentazione
¤  La classica rappresentazione dello spazio
d’indirizzamento è ottenuta semplicemente ruotando la
figura d...
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
...
Data segment
¤  Il data segment contiene variabili globali e variabili locali
static
Stack
Heap
x: 10
ctr: 0
Code
int x =...
Stack segment
¤  Lo stack mantiene in memoria le variabili locali ed i
parametri in ingresso alle funzioni
int main() {
i...
Stack segment
¤  Lo stack è organizzato come una pila, ogni volta che
una funzione viene invocata, viene aggiunto un nuov...
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 nuo...
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
¤  Variabi...
Creare oggetti dinamici
¤  Un oggetto dinamico deve quindi essere anonimo, in
altre parole, non deve avere un nome
Come p...
Creare oggetti dinamici
¤  Un oggetto dinamico deve quindi essere anonimo, in
altre parole, non deve avere un nome
¤  An...
Espressione new
¤  L’espressione new permette di creare oggetti dinamici
¤  Notare come:
¤  a sia una variabile locale,...
Espressione new
¤  L’espressione new permette di creare oggetti dinamici
¤  Ricorda: la variabile a non è l’oggetto dina...
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 quantitat...
Inizializzare oggetti dinamici
¤  Gli oggetti dinamici sono inizializzati a default
¤  I tipi built-in contengono quindi...
Inizializzare oggetti dinamici
¤  Sono possibili diversi tipi di inizializzazione:
¤  Inizializzazione diretta: l’oggett...
Modificare oggetti dinamici
¤  Per alterare oggetto dinamici si utilizza l’operatore di
indirezione *
int* a = new int;
i...
Distruggere oggetti dinamici
¤  Gli oggetti dinamici vanno esplicitamente distrutti
¤  Ogni oggetto allocato occupa part...
Espressione delete
¤  L’espressione delete permette di distruggere un oggetto
dinamico
¤  Dopo la delete, l’oggetto dina...
Espressione delete
Heap
Stack
a: int*
19 int
45
Espressione delete
¤  L’espressione delete esegue due operazioni:
¤  Invoca l’operatore delete, così da distrugge l’ogge...
Dangling pointers
¤  L’espressione delete distrugge l’oggetto dinamico
¤  Il corrispettivo puntatore non è quindi più va...
Dangling pointers
¤  L’espressione delete distrugge l’oggetto dinamico
¤  Il puntatore è diventato un dangling pointer
¤...
Dangling pointers
¤  La soluzione è quindi rafforzare il fatto che il puntatore
non sta più puntando a nulla
¤  Regola: ...
Strutture dinamiche
50
Strutture
¤  Le strutture generalizzano il concetto di array:
¤  Un array è una sequenza di elementi dello stesso tipo
¤...
Strutture
¤  Address è un tipo composto e definito dall’utente
¤  Una volta che il tipo Address è stato definito, è poss...
Inizializzare una struttura
¤  Dal C++11, è possibile inizializzare oggetti di tipo struttura
mediante una lista di inizi...
Member access operator
¤  I membri di una struttura sono accessibili mediante
l’operatore . (member access operator)
54
p...
Strutture dinamiche
¤  È possibile dichiarare strutture dinamiche mediante
l’espressione new
¤  L’espressione new restit...
Strutture dinamiche
¤  Esempio: la struttura polico_address è inizializzata a
default
56
Address* polico_address = new Ad...
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 inizi...
Accedere a membri di
una struttura dinamica
¤  Per accedere alla struttura dinamica è necessario:
¤  Accedere alla strut...
Accedere a membri di
una struttura dinamica
¤  Per accessi a membri di una struttura mediante
puntatore è disponibile una...
Distruggere una struttura dinamica
¤  Una struttura dinamica si distrugge mediante l’utilizzo
della espressione delete
61...
Array dinamici
Creare array dinamici
¤  Un array dinamico può essere creato mediante
l’espressione new[]
¤  L’espressione new restituis...
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 ...
Accedere ad un array dinamico
¤  L’accesso ad un array dinamico avviene secondo le
stesse modalità di un comune array
¤ ...
Distruggere un array dinamico
¤  Il programmatore è responsabile della distruzione di array
dinamici non più necessari
¤...
Distruggere un array dinamico
¤  L’uso delle [] è cruciale
¤  È l’unico modo per chiedere al compilatore di distruggere
...
Array di dimensioni variabili
Dimensione di un array
¤  La dimensione di un array automatico deve essere nota
a tempo di compilazione (compile time)
¤...
Dimensione di un array
vs stack
¤  Invocare una funzione significa impilare un nuovo frame
nello stack segment
void do_no...
Frame pointer e stack pointer
¤  Durante l’esecuzione di una funzione, possiamo
identificare due indirizzi importanti in ...
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
...
Frame pointer e stack pointer
¤  Gli indirizzi delle variabili locali della funzione in
esecuzione sono deducibili a part...
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...
Dimensione di un array
¤  Se richiediamo che le variabili abbiano dimensioni note a
priori tutti gli spiazzamenti sono ca...
Array di dimensioni variabili
¤  Non possiamo usare normali array, perchè verrebbero
allocati nello stack, totalmente ges...
Array di dimensioni variabili
¤  Al momento della creazione di un array dinamico, la
dimensione può essere una qualsiasi ...
Array dinamici multidimensionali
79
Array dinamici multidim.
¤  È possibile creare un array dinamico multidimensionale
attraverso l’espressione new[]
¤  L’e...
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 mat...
Nascondere il tipo dei sotto-array
¤  Dal C++11, è possibile far sì che sia il compilatore a
dedurre il tipo dato di una ...
Inizializzare array dinamici
multidimensionali
¤  Dal C++11, è possibile inizializzare un array dinamico
multidim. in man...
Distruggere array dinamici
multidimensionali
¤  Così come per i normali array dinamici, l’espressione
delete[] consente d...
Array dinamici multidim.
di dimensione variabile
¤  Tutte le dimensioni dell’array, con la sola eccezione della
prima, de...
Bibliografia
87
Bibliografia
¤  S. B. Lippman, J. Lajoie, B. E. Moo, C++ Primer (5th Ed.)
¤  B. Stroustrup, The C++ Programming Language...
Bibliografia
¤  C++ Reference, Zero initialization
http://en.cppreference.com/w/cpp/language/
zero_initialization
¤  C++...
Bibliografia
¤  Wikipedia, Data Segment
http://en.wikipedia.org/wiki/Data_segment
¤  University of Alberta, Understandin...
Bibliografia
¤  Stackoverflow FAQ, “How do I use arrays in C++?”
http://stackoverflow.com/questions/4810664/how-do-i-
use...
Upcoming SlideShare
Loading in...5
×

Gestione della memoria in C++

622

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
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
622
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Transcript of "Gestione della memoria in C++"

  1. 1. Gestione della memoria Ilio Catallo – Politecnico di Milano ilio.catallo@polimi.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* 19 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_initialization ¤  C++ Reference, Value initialization http://en.cppreference.com/w/cpp/language/ value_initialization ¤  C++ Reference, new expression http://en.cppreference.com/w/cpp/language/new ¤  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/ mem.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

×