9In che modo `std::vector` gestisce la capacità, la crescita, la riallocazione e la stabilità degli iteratori?
`std::vector` memorizza gli elementi in modo contiguo e tiene traccia sia della dimensione (`size`) che della capacità (`capacity`). La dimensione è il numero di elementi costruiti; la capacità è la quantità di memoria allocata per gli elementi disponibile prima che sia necessaria un'altra allocazione. Quando l'aggiunta di elementi supererebbe la capacità, il vettore alloca un blocco più grande, tipicamente utilizzando una strategia di crescita geometrica definita dall'implementazione, sposta o copia gli elementi esistenti, distrugge quelli vecchi e rilascia la vecchia memoria. `reserve(n)` aumenta la capacità senza modificare la dimensione, mentre `resize(n)` modifica la dimensione costruendo o distruggendo elementi. La riallocazione invalida tutti gli iteratori, i riferimenti e i puntatori agli elementi; anche senza riallocazione, operazioni come `insert` ed `erase` possono invalidare le posizioni in corrispondenza o successive al punto di modifica.
Prova a rispondere a questa domanda con un coach IA
10Quali regole di invalidazione dovresti conoscere per i container standard contigui e basati su nodi?
Le regole di invalidazione dipendono dal container e dall'operazione. I container contigui come vector e string hanno una stabilità fragile degli iteratori e dei riferimenti: l'aumento delle dimensioni può comportare una riallocazione e invalidare tutti gli iteratori, riferimenti e puntatori, e l'inserimento/rimozione (insert/erase) può spostare gli elementi e invalidare le posizioni in corrispondenza o dopo la modifica, anche senza riallocazione. I container ordinati basati su nodi come list, map, set e le loro varianti multi generalmente mantengono stabili iteratori e riferimenti agli elementi esistenti non rimossi durante l'inserimento; la rimozione di un elemento invalida l'iteratore/riferimento a quell'elemento rimosso. Anche i container non ordinati memorizzano gli elementi in nodi, quindi i riferimenti e i puntatori agli elementi sono generalmente stabili durante un rehash, ma il rehash invalida gli iteratori. deque ha regole speciali per l'archiviazione segmentata. In pratica, è consigliabile verificare lo specifico container e la specifica operazione prima di memorizzare iteratori o riferimenti durante le modifiche.
Prova a rispondere a questa domanda con un coach IA
11Confronta std::map, std::unordered_map e i contenitori in stile flat-map per le tabelle di ricerca nel backend.
std::map è un contenitore associativo ordinato, solitamente basato su alberi, con tempi logaritmici per ricerca, inserimento ed eliminazione; è utile quando contano l'iterazione ordinata, le query per intervalli o le garanzie di ordinamento. std::unordered_map è basato su tabelle hash con operazioni a tempo costante medio per chiavi esatte e nessun ordinamento delle chiavi; spesso rappresenta un'ottima scelta predefinita per tabelle di ricerca di grandi dimensioni e mutevoli, a patto che la funzione di hash sia efficiente. Un contenitore in stile flat-map archivia le coppie chiave/valore ordinate in modo contiguo, offrendo una buona località della cache e un'iterazione o ricerca binaria veloce, ma l'inserimento e l'eliminazione nel mezzo richiedono un tempo lineare. Per le tabelle di ricerca nel backend, la scelta dipende dalla necessità di ordinamento o query per intervalli, dalla predominanza di ricerche esatte, dalla frequenza delle mutazioni, dalla prevedibilità della latenza, dall'overhead di memoria e dal comportamento della cache.
Prova a rispondere a questa domanda con un coach IA
12Spiega std::optional e i tipici casi d'uso nel backend per rappresentare valori assenti.
std::optional<T> rappresenta un valore T contenuto al suo interno oppure nessun valore. Lo stato vuoto è rappresentato da std::nullopt; il codice può verificare la presenza del valore con has_value() o usando l'optional in un contesto booleano, accedere al valore tramite * o value(), e fornire un valore predefinito con value_or(). Nel codice di backend è utile per campi di database che ammettono valori nulli, campi opzionali di configurazione o di richiesta, mancate corrispondenze (miss) nella cache o nel repository quando l'assenza è prevista, e stati di dominio in cui un valore sentinella come -1 o una stringa vuota risulterebbe ambiguo. Modella l'assenza di un valore, non il polimorfismo o informazioni dettagliate sugli errori.
Prova a rispondere a questa domanda con un coach IA
13Cosa sono std::string_view e std::span, e quali rischi legati al ciclo di vita introducono le viste non proprietarie (non-owning views)?
std::string_view è una vista non proprietaria di una sequenza contigua di caratteri; std::span<T> è una vista non proprietaria di una sequenza contigua di T. Sono utili per parametri a zero copie e per le API basate su buffer perché trasportano un puntatore e una lunghezza senza allocare o possedere la memoria. Il rischio principale riguarda il ciclo di vita (lifetime): la memoria referenziata deve sopravvivere alla vista e non deve essere invalidata mentre la vista è in uso. Restituire o memorizzare una vista riferita a un oggetto temporaneo, a un oggetto locale, a un oggetto distrutto o a un contenitore riallocato può lasciare una vista penzolante (dangling view).
Prova a rispondere a questa domanda con un coach IA