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 types) как альтернативу исключениям для операций, которые могут завершиться ошибкой.
`std::expected<T, E>` представляет либо успешное значение `T`, либо явную ошибку `E`, делая сбой частью возвращаемого типа функции вместо использования механизма распространения исключений. Он полезен для операций с возможными ошибками, где сбои ожидаемы и вызывающий код должен обрабатывать их локально, таких как синтаксический анализ, валидация, сетевые вызовы, поиск в хранилище и серверные операции, для которых допустима повторная попытка после ошибки. Тип ошибки должен содержать структурированную информацию, такую как код ошибки, категория, возможность повторной попытки, сообщение или сопоставление с ошибками HTTP или удалённых вызовов процедур (RPC). Типы expected/outcome комбинируются путем проверки и распространения ошибок, а в API стиля C++23 могут использовать монадические операции, такие как `and_then`, `transform` и `or_else`, для построения цепочек шагов без глубоко вложенных условий. По сравнению с исключениями они делают поток управления и контракты API явными и поддерживают явную передачу ошибок в архитектурах без исключений. std::expected сам по себе не является переносимым типом для C или стабильным двоичным интерфейсом приложений (ABI) между различными наборами инструментов: используйте строго определённое представление данных на границе компонентов и учитывайте, что содержащиеся внутри операции или вызов value() при наличии ошибки все еще могут генерировать исключения; исключения по-прежнему могут быть уместны для редких, нелокальных или действительно исключительных сбоев в зависимости от принятых в проекте правил.
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-тренеру