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
9Explica std::expected o tipos de resultado equivalentes como alternativas a las excepciones para operaciones falibles.
`std::expected<T, E>` representa o bien 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 los errores son esperados y los llamadores deberían manejarlos localmente, como parsing, validación, llamadas de red, búsquedas en almacenamiento y operaciones backend reintentables. El tipo de error debería llevar información estructurada como un código de error, categoría, reintentabilidad, mensaje o mapeo HTTP/RPC. Los tipos expected/outcome se componen comprobando y propagando errores, y en APIs de estilo C++23 pueden usar operaciones monádicas como `and_then`, `transform` y `or_else` para encadenar pasos sin condicionales profundamente anidados. En comparación con las excepciones, hacen explícitos el flujo de control y los contratos de API y funcionan bien a través de límites sin excepciones o de ABI; las excepciones aún pueden ser 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