8Поясніть рівні безпеки винятків та те, як noexcept впливає на операції переміщення, контейнери та генерацію коду.
Рівні безпеки винятків (exception safety levels) описують, які твердження залишаються істинними, якщо операція викидає виняток. Базова гарантія (basic guarantee) означає, що інваріанти зберігаються, а ресурси не втрачаються, хоча стан міг змінитися. Строга гарантія (strong guarantee) означає семантику фіксації або відкоту (commit-or-rollback): у разі збою спостережуваний стан залишається незмінним. Гарантія відсутності винятків (nothrow guarantee) означає, що операція не викидає винятків. Поширені техніки включають RAII (Resource Acquisition Is Initialization), виконання роботи на тимчасових об'єктах, копіювання та обмін (copy-and-swap) і впорядкування змін таким чином, щоб фіксація відбувалася лише після успішного виконання операцій, що можуть викинути виняток. `noexcept` — це контракт: якщо функція з `noexcept` викидає виняток, викликається `std::terminate`. Це також впливає на узагальнений код і контейнери: наприклад, під час перерозподілу пам'яті (reallocation) `std::vector` може переміщувати елементи, коли конструктор переміщення є `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));
}
Відповісти на це запитання з ШІ-тренером
9Поясніть `std::expected` або еквівалентні типи результатів (outcome types) як альтернативу виняткам для операцій, що можуть завершитися помилкою.
`std::expected<T, E>` представляє або успішне значення `T`, або явну помилку `E`, роблячи збій частиною типу повернення функції замість покладання на поширення винятків. Це корисно для операцій, де помилки є очікуваними (fallible operations) й код, що їх викликає, повинен обробляти їх локально, наприклад: парсинг, валідація, мережеві виклики, пошук у сховищі та операції бекенду, які можна повторити. Тип помилки повинен містити структуровану інформацію, таку як код помилки, категорія, можливість повторної спроби, повідомлення або відображення на статуси HTTP (Hypertext Transfer Protocol) чи RPC (Remote Procedure Call). Типи очікуваних результатів (expected/outcome) дозволяють створювати композиції через перевірку та передачу помилок, а в API (Application Programming Interface) у стилі C++23 можуть використовувати монадичні операції, такі як `and_then`, `transform` та `or_else`, для створення ланцюжків кроків без глибоко вкладених умов. Порівняно з винятками, вони роблять потік керування та контракти API явними й добре працюють у середовищах без винятків або на межах ABI (Application Binary Interface); проте винятки можуть залишатися доречними для рідкісних, нелокальних або справді виняткових збоїв залежно від політики проєкту.
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)};
}
Відповісти на це запитання з ШІ-тренером