8Explica los niveles de seguridad ante excepciones y cómo noexcept afecta a las operaciones de movimiento, los contenedores y la generación de código.
Los niveles de seguridad ante excepciones describen qué sigue siendo cierto si una operación lanza. La garantía básica significa que se preservan los invariantes y no se filtran recursos, aunque el estado puede haber cambiado. La garantía fuerte significa semántica de commit-or-rollback: en caso de fallo, el estado observable no cambia. La garantía nothrow significa que la operación no lanza. Técnicas comunes incluyen RAII, realizar trabajo sobre temporales, copy-and-swap y ordenar las mutaciones para que el commit ocurra solo después de que el trabajo que puede lanzar haya tenido éxito. `noexcept` es un contrato: si una función `noexcept` lanza, se llama a `std::terminate`. También afecta al código genérico y a los contenedores: por ejemplo, durante una realocación `std::vector` puede mover elementos cuando el constructor de movimiento es `noexcept`; de lo contrario puede copiarlos, a menudo mediante `std::move_if_noexcept`, para preservar garantías de excepción. `noexcept` también puede ayudar a la generación de código u optimización al reducir las rutas necesarias de propagación de excepciones, pero solo cuando la promesa es correcta.
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));
}
Probar responder esta pregunta con un coach de IA
9Explique std::expected o tipos de resultado equivalentes como alternativas a las excepciones para operaciones falibles.
`std::expected<T, E>` representa un valor exitoso `T` o un error explícito `E`, haciendo que el fallo forme parte del tipo de retorno de la función en lugar de depender de la propagación de excepciones. Es útil para operaciones falibles donde se esperan errores y quienes llaman a la función deben manejarlos localmente, como análisis sintáctico (parsing), validación, llamadas de red, búsquedas de almacenamiento y operaciones de backend reintentables. El tipo de error debe contener información estructurada como un código de error, categoría, capacidad de reintento, mensaje o mapeo HTTP/RPC. Los tipos expected/outcome se componen comprobando y propagando errores, y en APIs de estilo C++23 pueden utilizar operaciones monádicas como `and_then`, `transform` y `or_else` para encadenar pasos sin condicionales profundamente anidados. En comparación con las excepciones, hacen que el flujo de control y los contratos de las API sean explícitos y admiten la propagación explícita de errores en diseños sin excepciones. std::expected no es en sí mismo un ABI de C portátil ni estable entre cadenas de herramientas: utilice una representación de límites definida y tenga en cuenta que las operaciones contenidas o value() en un error aún pueden lanzar excepciones; las excepciones pueden seguir siendo apropiadas para fallos raros, no locales o verdaderamente excepcionales según la política del proyecto.
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)};
}
Probar responder esta pregunta con un coach de IA