8Expliquez les niveaux de sûreté vis-à-vis des exceptions et la manière dont `noexcept` affecte les opérations de déplacement, les conteneurs et la génération de code.
Les niveaux de sûreté vis-à-vis des exceptions décrivent ce qui reste vrai si une opération lance une exception. La garantie de base signifie que les invariants sont préservés et que les ressources ne fuient pas, même si l’état a pu changer. La garantie forte signifie une sémantique de validation ou retour arrière : en cas d’échec, l’état observable est inchangé. La garantie nothrow signifie que l’opération ne lance pas d’exception. Les techniques courantes incluent RAII, le travail sur des temporaires, copy-and-swap et l’ordonnancement des mutations de sorte que la validation ne se produise qu’après la réussite du travail susceptible de lancer. `noexcept` est un contrat : si une fonction `noexcept` lance, `std::terminate` est appelé. Il affecte aussi le code générique et les conteneurs : par exemple, pendant une réallocation, `std::vector` peut déplacer les éléments lorsque le constructeur de déplacement est `noexcept` ; sinon il peut copier, souvent via `std::move_if_noexcept`, afin de préserver les garanties d’exception. `noexcept` peut aussi aider la génération de code ou l’optimisation en réduisant les chemins nécessaires de propagation d’exceptions, mais uniquement lorsque la promesse est correcte.
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));
}
Essayer de répondre à cette question avec un coach IA
9Expliquez std::expected ou les types de résultat équivalents comme alternatives aux exceptions pour des opérations susceptibles d'échouer.
std::expected<T,E> contient soit une valeur réussie T, soit une erreur explicite E : l'échec fait partie du type de retour plutôt que d'une propagation d'exception. Il convient aux erreurs attendues à traiter localement, comme analyse, validation, réseau, recherche en stockage ou opérations backend réessayables. E doit porter des informations structurées, code, catégorie, possibilité de nouvelle tentative, message ou correspondance avec le protocole de transfert hypertexte (HTTP) ou les appels de procédure à distance (RPC). Ces résultats se composent par vérification et propagation explicites ; les interfaces de programmation applicative (API) de style C++23 offrent and_then, transform et or_else pour chaîner sans conditions profondément imbriquées. Ils rendent flux et contrats explicites et permettent des architectures sans exceptions. std::expected n'est toutefois ni une interface binaire d'application (ABI) C portable ni une ABI stable entre chaînes d'outils : définir une représentation de frontière appropriée. Les opérations des valeurs contenues ou value() sur un état d'erreur peuvent encore lever des exceptions. Selon la politique du projet, celles-ci peuvent rester adaptées aux défaillances rares, non locales ou réellement exceptionnelles.
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)};
}
Essayer de répondre à cette question avec un coach IA