Salta al contenuto
Note per Studenti Esercizio - Quiz su constexpr, ordine di valutazione, dynamic_cast e lambda (primo appello 2022-23, quiz)

Esercizio - Quiz su constexpr, ordine di valutazione, dynamic_cast e lambda (primo appello 2022-23, quiz)

Esame

Quiz del primo 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 - Ereditarietà, is-a e has-a, slicing (primo appello 2022-23, teoria), Esercizio - Allocazione dinamica e layout della memoria (primo appello 2022-23, teoria), Esercizio - Predicati e algoritmi STL (primo appello 2022-23, teoria), Esercizio - La classe Complex (primo appello 2022-23, programmazione).

1) In C++, constexpr identifica:

affermazione V/F motivo
Una variabile costante il cui valore è noto a tempo di compilazione V è la definizione
Una variabile costante il cui valore è noto solo a tempo di esecuzione F quella è const
Una variabile costante che può essere solo di tipo std::string F qualunque tipo adatto (int, double, ...)
Una variabile costante senza tipo F ha sempre un tipo. Vedi C++ - tipi, variabili, espressioni e dichiarazioniun tipo definisce contenuto, intervallo di valori e operazioni; un oggetto è una regione di memoria con un tipo, il valore è la configurazione di bit letta in base al tipo, una variabile è un oggetto con un nome; inizializzazione (dare il primo valore) e assegnamento (cambiare il valore) sono diversi; le conversioni verso un tipo più capiente sono sicure, quelle verso un tipo meno capiente (narrowing, double->int, int->char) non lo sono e il compilatore le segnala di rado, ma la notazione con graffe {} le vieta; un'espressione calcola un valore da operandi e operatori, un lvalue è ciò che può stare a sinistra di =, constexpr vuole un valore noto in compilazione mentre const solo un valore che non cambia; gli operatori con side effect (++, --, +=) non vanno mischiati con altri usi della stessa variabile nella stessa espressione perché l'ordine di valutazione non è definito; una dichiarazione introduce un nome e un tipo, una definizione fornisce anche l'entità (memoria per una variabile, corpo per una funzione).C++ - tipi, variabili, espressioni e dichiarazioni →

2) In C++, le espressioni:

affermazione V/F motivo
Hanno un ordine di valutazione definito dalla standard library F l'ordine di valutazione degli operandi non è definito (e non lo stabilisce la libreria)
Possono modificare i loro operandi V gli operatori con side effect (++, +=, =)
Sono il più piccolo elemento usato per esprimere la computazione V
Possono essere combinate con operatori per formare espressioni più complesse V (length + width) * 2

3) v[i] = ++i;

affermazione V/F motivo
Il valore assegnato all'ii-esimo elemento di v è sempre pari a i+1i+1 F l'ordine di valutazione di v[i] e ++i non è definito: l'indice può essere il vecchio o il nuovo valore
Il valore assegnato all'ii-esimo elemento non è conoscibile a priori V comportamento non definito
L'operatore ++ non ha side effect F modifica i
Può generare segmentation fault V se l'indice calcolato esce dal vettore

4) In C++, una definizione:

affermazione V/F motivo
Fornisce tutte le informazioni necessarie per creare l'entità nella sua interezza V
Se riguarda una variabile, significa riservare memoria per essa V
Se riguarda una funzione, significa fornire il corpo di essa V
Se riguarda una classe, significa fornire tutti i membri e le funzioni membro della classe V la dichiarazione dà solo il nome. Vedi C++ - tipi, variabili, espressioni e dichiarazioniun tipo definisce contenuto, intervallo di valori e operazioni; un oggetto è una regione di memoria con un tipo, il valore è la configurazione di bit letta in base al tipo, una variabile è un oggetto con un nome; inizializzazione (dare il primo valore) e assegnamento (cambiare il valore) sono diversi; le conversioni verso un tipo più capiente sono sicure, quelle verso un tipo meno capiente (narrowing, double->int, int->char) non lo sono e il compilatore le segnala di rado, ma la notazione con graffe {} le vieta; un'espressione calcola un valore da operandi e operatori, un lvalue è ciò che può stare a sinistra di =, constexpr vuole un valore noto in compilazione mentre const solo un valore che non cambia; gli operatori con side effect (++, --, +=) non vanno mischiati con altri usi della stessa variabile nella stessa espressione perché l'ordine di valutazione non è definito; una dichiarazione introduce un nome e un tipo, una definizione fornisce anche l'entità (memoria per una variabile, corpo per una funzione).C++ - tipi, variabili, espressioni e dichiarazioni →

5) std::vector<int> vi(10); std::vector<int> vi2 {1, 2, 3, 4}; const int x2 {9};

affermazione V/F motivo
vi di 10 elementi a 0, vi2 di 4 elementi a 0, x2 a 9 F vi2 ha i valori 1, 2, 3, 4
vi di 1 elemento inizializzato a 10, vi2 di 4 elementi non inizializzati, x2 costante a 9 F le parentesi tonde (10) danno 10 elementi, non uno; vi2 è inizializzato
vi di 10 elementi a 0, vi2 di 4 elementi inizializzati ai valori 1, 2, 3, 4 e x2 a 9 V tonde = dimensione, graffe = lista di valori
Dà errore in fase di compilazione F tre inizializzazioni lecite

6) Una funzione che implementa l'overloading di un operatore:

affermazione V/F motivo
È implementabile solo per gli UDT V almeno un operando deve essere di tipo definito dall'utente (int operator+(int, int) è vietato). Vedi C++ - enumerazioni e overloading degli operatoriun'enumerazione è un tipo definito dall'utente che specifica un insieme di valori simbolici (enumeratori); enum class crea uno scope (Month::jan), non si converte implicitamente in int, e i valori partono da 0 o dal valore del precedente più uno; l'overloading degli operatori permette di definire gli operatori esistenti per tipi definiti dall'utente (almeno un operando UDT, stesso numero di operandi e stessa sintassi) scrivendo una funzione di nome operator+, operator++, operator[], ...; si può fare con una helper function (due argomenti per un operatore binario, il primo può essere di qualunque tipo) o con una funzione membro (un argomento in meno, perché il primo operando è l'oggetto, quindi l'UDT deve stare a sinistra: T + int sì, int + T no); << e >> sono helper function che prendono e restituiscono ostream& e istream&; ++ ha due forme (pre e post, quest'ultima con un int fittizio); gli operatori più utili sono =, ==, !=, <, [], ().C++ - enumerazioni e overloading degli operatori →
Può alterare il numero degli operandi rispetto allo stesso operatore implementato per tipi built-in F stesso numero di operandi e stessa sintassi
Ha un numero di argomenti diverso a seconda che sia funzione membro o helper function V un argomento in meno se membro (il primo è this)
Se non implementata dal programmatore, è generata automaticamente dal compilatore se l'operatore è utilizzato nel codice F non c'è generazione automatica (le uniche eccezioni sono le operazioni speciali di copia e spostamento dell'assegnamento)

7) Il dynamic_cast:

8) L'iteratore di un container STL:

affermazione V/F motivo
È inizializzato a nullptr se l'allocazione dinamica del container non va a buon fine F gli iteratori non sono legati alla riuscita dell'allocazione
Indica un elemento del container, a cui si può accedere usando l'operatore * V
Può riferirsi a un elemento non esistente del container V end() è dopo l'ultimo elemento: confrontabile, non dereferenziabile
È una classe template V è un tipo definito dal container template (list<Elem>::iterator nelle slide); per vector può essere realizzato come un puntatore, ma è comunque definito per ogni Elem. 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) →

9) Una lambda expression (o lambda function):

affermazione V/F motivo
È una funzione di cui non è definito il nome V funzione anonima definita localmente
Può accettare argomenti V [](int x) { ... }
Non ha un tipo restituito F ce l'ha; si può specificare (-> double) o è dedotto
È in grado di catturare le variabili locali per riferimento con la clause [=] F [=] cattura per valore; per riferimento è [&]. Vedi STL - algoritmi, predicati e lambdaLa STL ha circa 80 algoritmi generici (header e ) che lavorano su sequenze [first, last) di qualunque contenitore tramite iteratori: find/find_if, count/count_if, sort, copy/copy_if/unique_copy, merge, equal_range, equal, accumulate, inner_product. find cerca un valore e restituisce l'iteratore alla prima occorrenza o end(); find_if verifica un predicato (funzione che restituisce bool) passato come puntatore a funzione, function object (classe con operator()) o lambda expression. Una variabile globale per passare la soglia al predicato è da evitare; il function object la memorizza in un dato membro. Una lambda cattura -> tipo { corpo } definisce la funzione sul posto e può catturare le variabili locali per valore ([=], [x]) o per riferimento ([&], [&x]). sort(b, e) ordina con < e sort(b, e, cmp) con un criterio, solo su iteratori random access; copy richiede spazio a destinazione.STL - algoritmi, predicati e lambda →

10) Uno std::unique_ptr:

Versione ripasso

Teoria collegata