Salta al contenuto
Note per Studenti Esercizio - Quiz su record di attivazione, new[], dangling pointer e struct (terzo appello 2022-23, quiz)

Esercizio - Quiz su record di attivazione, new[], dangling pointer e struct (terzo appello 2022-23, quiz)

Esame

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 +1+1, sbagliata −0.25-0.25, non data 00). 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]:

affermazione V/F motivo
Per effettuare la deallocazione si utilizza l'istruzione delete[] students; F students è il tipo: si cancella il puntatore, delete[] student_list;
Provoca una chiamata al sistema operativo V l'allocazione dinamica passa dal sistema operativo (costo non trascurabile)
Se size è troppo grande, può causare un overflow nello stack F la memoria è nell'heap, non nello stack: semmai new fallisce (std::bad_alloc)
Se ne deduce che student_list è un oggetto std::list<student> F è un puntatore a students (new T[n] restituisce T*). Vedi 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) 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:

affermazione V/F motivo
Possono essere uguali, ovvero begin() == end() può essere true V container vuoto
begin punta al primo elemento, end all'ultimo elemento F end è dopo l'ultimo
Sono definiti anche se è possibile indicizzare il container con l'operatore [] V tutti i container STL li hanno, vector compreso
Sono definiti solo se esiste almeno un elemento nel container F sono definiti sempre. Vedi STL - sequenze, iteratori e container (vector, list, string)La STL (Standard Template Library) fornisce contenitori (vector, list, map, ...) e algoritmi generici (sort, find, accumulate, ...) tenuti insieme da una interfaccia unificata: la sequenza, un intervallo [begin, end) di elementi gestito tramite iteratori (oggetti che identificano un elemento: * dereferenzia, ++ avanza, == e != confrontano; end è il primo elemento dopo l'ultimo, quindi una sequenza vuota ha begin == end). Gli algoritmi conoscono solo gli iteratori e i contenitori espongono solo iteratori, così i due mondi sono disaccoppiati e cambiare contenitore non cambia l'algoritmo. Un iteratore di lista è una classe annidata con un puntatore al nodo; auto deduce il tipo dell'iteratore. vector (contiguo, [] e at(), insert/erase costosi e che invalidano gli iteratori), string (un vector di char con + e +=), list (nodi concatenati, insert/erase senza spostare gli altri elementi, niente []) e char[] (array C: dimensione fissa, niente iteratori, == confronta i puntatori) a confronto.STL - sequenze, iteratori e container (vector, list, string) →

6) La conversione di una variabile da float a double:

7) Il distruttore di una classe in C++:

affermazione V/F motivo
Se non ridefinito dall'utente, di default libera il Free Store utilizzato dalla classe F quello generato non libera la memoria puntata da puntatori nudi; distrugge solo i membri
Viene chiamato unicamente quando si usa l'operatore delete F anche all'uscita dallo scope
Se non definito dall'utente, viene implementato automaticamente dal compilatore V
Può avere degli argomenti definiti dall'utente F nessun parametro: ~T(). Vedi 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 →

8) La compilazione di un progetto C++:

affermazione V/F motivo
Il compilatore può ottimizzare il codice in autonomia V purché il comportamento resti lo stesso (-O2)
Un errore di linking si può verificare quando una parte del software esterna al progetto (ad esempio una libreria) è mancante V undefined reference
I commenti presenti nel codice vengono tradotti in linguaggio macchina F spariscono nella compilazione
Il compilatore gcc/g++ di default segnala le conversioni non valide fra tipi diversi V le conversioni non valide (per esempio int →\to string) sono errori; quelle valide ma non sicure (narrowing) non lo sono, se non con {}. Vedi 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) Un'enumerazione:

10) In C++, una struct:

Versione ripasso

Teoria collegata