9Kako std::vector upravlja kapacitetom, rastom, realokacijom i stabilnošću iteratora?
std::vector skladišti elemente uzastopno u memoriji i prati i veličinu i kapacitet. size predstavlja broj konstruisanih elemenata, dok je capacity količina alocirane memorije za skladištenje elemenata pre nego što bude potrebna nova alokacija. Kada bi dodavanje elemenata premašilo kapacitet, vector alocira veći memorijski blok, obično koristeći strategiju geometrijskog rasta definisanu implementacijom, premešta ili kopira postojeće elemente, uništava stare i oslobađa prethodnu memoriju. reserve(n) povećava kapacitet bez promene veličine, dok resize(n) menja veličinu konstruisanjem ili uništavanjem elemenata. Realokacija poništava sve iteratore, reference i pokazivače na elemente; čak i bez realokacije, operacije kao što su insert i erase mogu poništiti pozicije na mestu modifikacije ili nakon njega.
std::vector<int> v;
v.reserve(100); // capacity >= 100, size == 0
v.push_back(1); // size == 1
v.resize(10); // size == 10, adds nine zero-initialized ints
std::cout << v.size() << " " << v.capacity() << "\n";
Pokušajte da odgovorite na ovo pitanje sa AI trenerom
10Koja pravila o nevalidnosti iteratora i referenci treba poznavati za kontinualne kontejnere i kontejnere zasnovane na čvorovima u standardnoj biblioteci?
Pravila o invalidaciji zavise od kontejnera i operacije. Kontinualni kontejneri kao što su `vector` i `string` imaju krhku stabilnost iteratora i referenci: povećanje kapaciteta može dovesti do realokacije i učiniti nevažećim sve iteratore, reference i pokazivače, dok operacije `insert` i `erase` mogu pomeriti elemente i poništiti pozicije na mestu promene ili nakon njega, čak i bez realokacije. Uređeni kontejneri zasnovani na čvorovima kao što su `list`, `map`, `set` i njihove `multi` varijante uglavnom zadržavaju stabilnost iteratora i referenci na postojeće, neobrisane elemente prilikom umetanja (`insert`); brisanje elementa (`erase`) čini nevažećim iterator i referencu samo na taj obrisani element. Neuređeni kontejneri takođe skladište elemente u čvorovima, pa su reference i pokazivači na elemente uglavnom stabilni tokom ponovnog heširanja (`rehash`), ali `rehash` poništava iteratore. `deque` ima posebna pravila zbog segmentiranog skladištenja. U praksi, proverite specifičan kontejner i operaciju pre nego što čuvate iteratore ili reference tokom modifikacija.
std::map<int, std::string> m = {{1,"a"}, {2,"b"}, {3,"c"}};
for (auto it = m.begin(); it != m.end(); ) {
if (it->first % 2 == 1)
it = m.erase(it); // returns next iterator
else
++it;
}
Pokušajte da odgovorite na ovo pitanje sa AI trenerom
11Uporedite `std::map`, `std::unordered_map` i kontejnere u stilu flat-map za tabele pretrage na backendu.
`std::map` je uređeni asocijativni kontejner, obično zasnovan na stablu, sa logaritamskom složenošću pretrage, umetanja i brisanja; koristan je kada su važni sortirana iteracija, upiti po opsegu ili garancije redosleda. `std::unordered_map` je zasnovan na heš tabeli sa prosečnim konstantnim vremenom za operacije sa tačnim ključem i bez redosleda ključeva; često je dobar podrazumevani izbor za velike promenljive tabele pretrage kada je heš funkcija dobra. Kontejner u stilu flat-map čuva sortirane parove ključ/vrednost u kontinualnoj memoriji, pružajući dobru lokalnost keša i brzu iteraciju/binarnu pretragu, ali su umetanje i brisanje u sredini linearni. Za tabele pretrage na backendu, izbor zavisi od toga da li opterećenje zahteva uređenost/opsege, uglavnom tačne pretrage, česte izmene, predvidivo kašnjenje, memorijsko zauzeće i ponašanje keša.
// Exact lookup, frequently updated:
std::unordered_map<std::string, User> users_by_id;
// Need sorted iteration or lower_bound/range queries:
std::map<std::string, User> users_by_id_ordered;
// Build once, query many times: vector sorted by key is a common flat-map style.
std::vector<std::pair<std::string, User>> users;
std::sort(users.begin(), users.end(), [](auto const& a, auto const& b) {
return a.first < b.first;
});
auto it = std::lower_bound(users.begin(), users.end(), std::string_view{"u123"},
[](auto const& p, std::string_view key) { return p.first < key; });
Pokušajte da odgovorite na ovo pitanje sa AI trenerom
12Objasnite `std::optional` i tipične slučajeve upotrebe na serverskoj strani za predstavljanje nepostojećih vrednosti.
`std::optional<T>` predstavlja ili sadržanu vrednost tipa `T` ili odsustvo vrednosti. Prazno stanje je predstavljeno pomoću `std::nullopt`; u kodu se može proveriti `has_value()` ili koristiti `std::optional` u logičkom (boolean) kontekstu, pristupiti vrednosti preko operatora `*` ili metode `value()`, kao i proslediti podrazumevana vrednost pomoću `value_or()`. U serverskom kodu je koristan za kolone baze podataka koje mogu biti null (nullable), opciona polja u zahtevima ili konfiguraciji, promašaje u kešu ili repozitorijumu gde je odsustvo očekivano, kao i za domenska stanja gde bi kontrolna vrednost (sentinel) poput `-1` ili praznog stringa bila dvosmislena. On modeluje odsustvo vrednosti, a ne polimorfizam ili detaljne informacije o greškama.
struct UserProfile {
std::string id;
std::optional<std::string> display_name; // absent if user has not set it
};
std::string label(UserProfile const& u) {
return u.display_name.value_or("anonymous");
}
Pokušajte da odgovorite na ovo pitanje sa AI trenerom
13Šta su std::string_view i std::span, i kakve opasnosti po životni vek uvode pogledi bez vlasništva?
`std::string_view` je pogled bez vlasništva nad neprekidnim nizom karaktera; `std::span<T>` je pogled bez vlasništva nad neprekidnim nizom elemenata tipa T. Korisni su za parametre bez kopiranja (zero-copy) i API-je za bafere jer sadrže pokazivač i dužinu bez alokacije ili preuzimanja vlasništva nad memorijom. Glavna opasnost se odnosi na životni vek: memorija na koju pokazuju mora nadživeti sam pogled i ne sme postati nevažeća dok se pogled koristi. Vraćanje ili čuvanje pogleda koji pokazuje na privremeni objekat, lokalni objekat, uništeni objekat ili realocirani kontejner može ostaviti viseći pogled (dangling view).
std::string_view bad() {
std::string s = "hello";
return std::string_view{s}; // dangling after return
}
void ok(std::string_view name) {
// safe only during this call if caller's data outlives the call
}
Pokušajte da odgovorite na ovo pitanje sa AI trenerom