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

No Downloads
Views
Total views
1,333
On SlideShare
0
From Embeds
0
Number of Embeds
51
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

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

×