8Объясните уровни exception safety и то, как noexcept влияет на move-операции, контейнеры и генерацию кода.
Уровни exception safety описывают, что остаётся истинным, если операция бросает исключение. Базовая гарантия (basic guarantee) означает, что инварианты сохранены и ресурсы не утекают, хотя состояние могло измениться. Сильная гарантия (strong guarantee) означает семантику commit-or-откат: при сбое наблюдаемое состояние не меняется. Гарантия nothrow означает, что операция не бросает. Типичные техники включают RAII, выполнение на временных объектах, copy-and-swap и упорядочивание мутаций так, чтобы commit происходил только после успешного завершения работы, которая может бросить. `noexcept` — это контракт: если функция `noexcept` бросает, вызывается `std::terminate`. Он также влияет на generic-код и контейнеры: например, при реаллокации `std::vector` может перемещать элементы, когда move-конструктор `noexcept`; иначе может копировать, часто через `std::move_if_noexcept`, чтобы сохранить гарантии исключений. `noexcept` также может помочь генерации кода или оптимизации, сокращая нужные пути распространения исключений, но только когда обещание корректно.
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));
}
Попробовать ответить на вопрос AI-тренеру
9Объясните std::expected или эквивалентные outcome-типы как альтернативу исключениям для fallible-операций.
`std::expected<T, E>` представляет либо успешное значение `T`, либо явную ошибку `E`, делая сбой частью возвращаемого типа функции вместо опоры на распространение исключений. Это полезно для fallible-операций, где ошибки ожидаемы и вызывающий код должен обрабатывать их локально: парсинг, валидация, сетевые вызовы, lookup в storage и повторяемые backend-операции. Тип ошибки должен нести структурированную информацию: код ошибки, категорию, retryability, сообщение или отображение в HTTP/RPC. Типы expected/outcome компонуются проверкой и распространением ошибок, а в API в стиле C++23 могут использовать монадические операции вроде `and_then`, `transform` и `or_else`, чтобы связывать шаги без глубокой вложенности условий. По сравнению с исключениями они делают поток управления и контракты API явными и хорошо работают через границы без исключений или ABI; исключения по-прежнему могут быть уместны для редких, нелокальных или действительно исключительных сбоев в зависимости от политики проекта.
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)};
}
Попробовать ответить на вопрос AI-тренеру