Esercizio - Quiz su record di attivazione, new[], dangling pointer e struct (terzo appello 2022-23, quiz)
Quiz del terzo appello del corso di Laboratorio di Programmazione, Ing. Informatica UniPD, a.a. 2022-23 (90 minuti): dieci domande a quattro affermazioni vero/falso (giusta , sbagliata , non data ). Gli altri esercizi dell'appello: Esercizio - Array stile C, vector e la classe MyArray (terzo appello 2022-23, teoria), Esercizio - Scope e durata della memorizzazione (terzo appello 2022-23, teoria), Esercizio - RAII e garanzie sulle eccezioni (terzo appello 2022-23, teoria), Esercizio - Copiare da array a array dinamico senza delete (terzo appello 2022-23, programmazione).
1) Il record di attivazione di una funzione:
2) L'allocazione student_list = new students[size]:
3) Il problema del dangling pointer:
| affermazione | V/F | motivo |
|---|---|---|
| Può essere causato da un errore in fase di deallocazione | V | dopo una delete il puntatore resta con il vecchio valore, non più valido (o si restituisce l'indirizzo di una locale) |
| Causa un errore di compilazione | F | è un errore a run-time |
| Può causare il lancio di un'eccezione | F | l'uso di un puntatore pendente è comportamento indefinito (spesso un crash), non un'eccezione C++ |
| Si verifica solo in una chiamata a funzione | F | ovunque si usi un puntatore dopo delete o un oggetto fuori scope |
4) int a = 100, b = 200; int *p = &a, *q = &b; p = q;
5) Gli iteratori begin e end di un container STL:
6) La conversione di una variabile da float a double:
7) Il distruttore di una classe in C++:
8) La compilazione di un progetto C++:
9) Un'enumerazione:
10) In C++, una struct:
Versione ripasso
- 1 RA: V, F, F, V. Creato a ogni chiamata, nello stack, uno per chiamata, dimensione dipendente dalla funzione. C++ - chiamate a funzione e layout della memoriauna chiamata a funzione crea un record di attivazione (RA) con una copia dei parametri e le variabili locali, impilato nello stack (LIFO) e tolto all'uscita; la dimensione dipende dalle variabili locali e il tempo per inserirlo è costante; il processo ha cinque regioni di memoria: text (istruzioni, spesso read-only), initialized data (globali e statiche inizializzate), uninitialized data o BSS (globali e statiche non inizializzate, azzerate dal sistema), stack (RA) e heap (allocazione dinamica con new e delete); la durata (storage duration) di una variabile è diversa dallo scope: le globali e le static sono statiche (esistono per tutto il programma, inizializzate una volta), le locali sono automatiche (create all'entrata nel blocco, distrutte in ordine inverso all'uscita); le globali sono inizializzate prima del main ma l'ordine fra file diversi non è definito.C++ - chiamate a funzione e layout della memoria →.
- 2
student_list = new students[size]: F, V, F, F. Si libera condelete[] student_list;(non il nome del tipo); chiamata al sistema operativo; è heap (nessun overflow dello stack);student_listè un puntatore. C++ - allocazione dinamica della memoria con new e deletela memoria dinamica si prende dal free store (heap) con new, che restituisce un puntatore all'oggetto o al primo elemento dell'array (new T, new T[n], con inizializzatori {}), e si restituisce con delete (per new) e delete[] (per new[]); il puntatore non sa quanti elementi ci sono, la memoria non ha nome e non ha controllo dei limiti; in C++ non c'è garbage collector (scelta per efficienza e controllo), quindi un'area che perde ogni riferimento diventa garbage e produce un memory leak, e gli errori tipici sono la doppia cancellazione e il dangling pointer (si mette il puntatore a nullptr dopo delete); il distruttore ~T() è chiamato dal compilatore quando l'oggetto esce dallo scope o con delete e libera le risorse, per cui una classe come vector acquisisce la memoria nel costruttore e la rilascia nel distruttore; new alloca e chiama il costruttore, delete chiama il distruttore e libera; operator[] con due versioni (T& e const) dà accesso in lettura e scrittura al buffer; si alloca dinamicamente solo se serve davvero (memoria grande, dimensione nota a run-time, durata controllata).C++ - allocazione dinamica della memoria con new e delete →. - 3 Dangling pointer: V, F, F, F. Dopo una
delete/uso di memoria non più valida; errore a run-time (non di compilazione, non un'eccezione); ovunque, non solo nelle funzioni. - 4
p = q: F, V, F, F. Si copiano gli indirizzi:ppunta ab;aebrestano distinte e raggiungibili (nessun garbage). C++ - puntatori, array e castun puntatore è una variabile che contiene un indirizzo di memoria e sa il tipo dell'oggetto puntato (T*); si ottiene l'indirizzo con & e si accede al dato con * (dereference, un lvalue), nullptr indica nessun oggetto e due puntatori a tipi diversi sono tipi diversi; void* è un puntatore a memoria grezza (accetta qualsiasi puntatore ma non si dereferenzia) e i cast (static_cast, reinterpret_cast, const_cast) servono per interfacciarsi con hardware e codice non modificabile; il puntatore, a differenza della reference, si può spostare, può essere nullptr e va dereferenziato, e assegnarlo copia l'indirizzo (shallow copy) mentre assegnare una reference copia l'oggetto; un array C è una sequenza contigua di elementi dello stesso tipo, con dimensione costante, senza controllo dei limiti, che passato a una funzione decade in un puntatore al primo elemento; l'aritmetica dei puntatori somma o sottrae interi spostando di n elementi (non di n byte) e la differenza fra puntatori è in elementi; gli errori classici sono nullptr, puntatori non inizializzati, accessi fuori dai limiti e puntatori a oggetti usciti dallo scope.C++ - puntatori, array e cast →. - 5
begin/end: V, F, V, F. Possono coincidere (vuoto);endè dopo l'ultimo; definiti sempre, anche pervector. - 6
floatdouble: V, F, F, F. Sicura, senza dipendere dall'architettura. - 7 Distruttore: F, F, V, F. Il generato non libera la memoria puntata; chiamato anche all'uscita dallo scope; nessun argomento.
- 8 Compilazione: V, V, F, V. Ottimizza; libreria mancante = linking; i commenti non finiscono nel codice; tipi non validi = errori. C++ - introduzione, compilazione e linkingC++ è un linguaggio compilato e standard che dà controllo totale sulla macchina (basso livello) e strumenti di astrazione (alto livello); un programma parte da main, usa gli stream (std::cout << ...) e le direttive del preprocessore (#include); il passaggio da sorgente a eseguibile ha tre fasi, preprocessore (espande #include e macro), compilatore (controlla sintassi e tipi e produce un file oggetto in codice macchina) e linker (unisce i file oggetto e le librerie risolvendo i nomi); gli errori di sintassi e di tipo sono del compilatore, i simboli dichiarati ma non definiti (undefined reference) sono del linker; si compila da riga di comando con g++ -o eseguibile sorgente.cpp -lLibreria.C++ - introduzione, compilazione e linking →.
- 9 Enumerazione: F, V, F, V. Niente membri;
enum classcrea uno scope; più espressiva, non più efficiente. - 10
struct: F, F, F, F. Può essere vuota, membri pubblici di default, classi annidate lecite,.e->secondo il caso. C++ - classi, membri e invariantiuna classe è un tipo definito dal programmatore che rappresenta un concetto con una rappresentazione (dati membro) e delle operazioni (funzioni membro); l'interfaccia pubblica separa chi usa la classe da chi la implementa e i dati privati sono modificabili solo tramite l'interfaccia; struct è una class con membri pubblici di default; l'invariante è la regola che definisce gli stati validi, e il costruttore deve stabilirlo e ogni funzione membro conservarlo; il costruttore (stesso nome della classe) inizializza con una lista di inizializzazione e, se i dati non sono validi, lancia un'eccezione, l'unico modo per far fallire un costruttore; le funzioni membro si definiscono fuori dalla classe (solo le brevissime dentro, dove sono inline); le funzioni che non modificano l'oggetto sono dichiarate const; le funzioni che si possono scrivere con la sola interfaccia pubblica (operator==, next_sunday) sono helper function esterne, spesso nello stesso namespace.C++ - classi, membri e invarianti →.
Teoria collegata
- C++ - chiamate a funzione e layout della memoria
- C++ - allocazione dinamica della memoria con new e delete
- C++ - puntatori, array e cast
- STL - sequenze, iteratori e container (vector, list, string)
- C++ - tipi, variabili, espressioni e dichiarazioni
- C++ - introduzione, compilazione e linking
- C++ - enumerazioni e overloading degli operatori
- C++ - classi, membri e invarianti