8Forklar niveauer for undtagelsessikkerhed (exception safety), og hvordan `noexcept` påvirker flytteoperationer, beholdere og kodegenerering.
Niveauer for undtagelsessikkerhed beskriver, hvad der forbliver sandt, hvis en operation kaster en undtagelse. Den grundlæggende garanti (basic guarantee) betyder, at invarianter bevares, og ressourcer ikke lækkes, selvom tilstanden kan have ændret sig. Den stærke garanti (strong guarantee) betyder commit-eller-rollback-semantik: ved fejl forbliver den observerbare tilstand uændret. Nothrow-garantien (nothrow guarantee) betyder, at operationen ikke kaster undtagelser. Almindelige teknikker omfatter RAII (Resource Acquisition Is Initialization), udførelse af arbejde på midlertidige objekter, kopier-og-byt (copy-and-swap), samt at ordne ændringer, så bekræftelsen (commit) først sker, når arbejde, der kan kaste undtagelser, er fuldført. `noexcept` er en kontrakt: hvis en `noexcept`-funktion kaster en undtagelse, kaldes `std::terminate`. Det påvirker også generisk kode og beholdere: for eksempel kan `std::vector` under genallokering flytte elementer, når flytte-konstruktøren (move constructor) er `noexcept`; ellers kopierer den muligvis, ofte via `std::move_if_noexcept`, for at bevare undtagelsesgarantier. `noexcept` kan også hjælpe med kodegenerering eller optimering ved at reducere de nødvendige stier til propagering af undtagelser, men kun når løftet er korrekt.
std::vector<T> v;
// During reallocation, an implementation may effectively do:
T* dest = allocate(new_cap);
for (T& x : old_storage) {
construct(dest++, std::move_if_noexcept(x));
}
Prøv at besvare dette spørgsmål med en AI-coach
9Forklar `std::expected` eller tilsvarende resultatyper som alternativer til undtagelser (exceptions) for fejlbarlige operationer.
`std::expected<T, E>` repræsenterer enten en succesfuld værdi `T` eller en eksplicit fejl `E`, hvilket gør fejl til en del af funktionens returtype i stedet for at bero på udbredelse af undtagelser. Det er nyttigt for fejlbarlige operationer, hvor fejl forventes, og hvor kalderen bør håndtere dem lokalt, f.eks. ved parsing, validering, netværkskald, opslag i lagre og backend-operationer, der kan forsøges igen. Fejltypen bør bære struktureret information såsom en fejlkode, kategori, om den kan forsøges igen, en besked eller HTTP/RPC-mapping. Typer som `expected` eller `outcome` kan sammensættes ved at kontrollere og videregive fejl, og i C++23-lignende API'er kan man bruge monadiske operationer som `and_then`, `transform` og `or_else` til at sammenkæde trin uden dybt indlejrede betingelser. Sammenlignet med undtagelser gør de kontrolstrømme og API-kontrakter eksplicitte og fungerer godt på tværs af undtagelsesfrie grænser eller ABI-grænser; undtagelser kan stadig være passende for sjældne, ikke-lokale eller sandt ekstraordinære fejl afhængigt af projektets politik.
enum class Errc { BadRequest, NotFound, Timeout, DbUnavailable };
struct Error {
Errc code;
bool retryable;
std::string message;
};
std::expected<User, Error> load_user(UserId id);
HttpResponse handle(UserId id) {
auto user = load_user(id);
if (!user) {
switch (user.error().code) {
case Errc::BadRequest: return {400, user.error().message};
case Errc::NotFound: return {404, "not found"};
case Errc::Timeout: return {503, "try again"};
case Errc::DbUnavailable: return {503, "service unavailable"};
}
}
return {200, serialize(*user)};
}
Prøv at besvare dette spørgsmål med en AI-coach