Лабораторная работа №8. Ошибки, исключения и std::expected
Цель занятия: научиться выбирать способ сообщения об ошибке, генерировать и перехватывать стандартные исключения и не оставлять объект в частично изменённом состоянии.
Необходимые темы и конструкции C++:
- проверка предусловий и возврат признака ошибки
throw,try,catch- стандартные исключения
std::invalid_argument,std::domain_error,std::out_of_range - перехват исключения по константной ссылке
- распространение исключения по цепочке вызовов
Структура проекта
Разместите решение в следующих файлах:
main.cppsafe_tasks.hsafe_tasks.cpp
Общие требования
- Соблюдайте указанные сигнатуры функций: ввод и вывод организуйте в
main. - Проверьте каждую функцию не менее чем на трёх наборах данных, включая граничный случай.
- Не используйте средства, которые не перечислены в разделе необходимых тем, если условие прямо их не разрешает.
std::expected и noexcept рассматривались обзорно. В обязательных заданиях и контрольных работах этого семестра они не используются.Основные задания
-
Результат через признак ошибки
Вычислить квадратный корень числа без исключений. Функция возвращает признак успеха, а результат записывает через ссылку.
Требуемая сигнатура:
bool try_sqrt(double value, double& result);Требования:
- При отрицательном аргументе не изменяйте
result. - Сравните удобство вызова с вариантом, возвращающим специальное числовое значение.
Входные данные / вызов Результат result=10; try_sqrt(-4, result)false; result=10 - При отрицательном аргументе не изменяйте
-
Безопасный доступ к массиву
Вернуть элемент статического массива по индексу. При пустом указателе сгенерировать
std::invalid_argument, при неверном индексе —std::out_of_range.Требуемая сигнатура:
int element_at(const int* data, int size, int index);Требования:
- В вызывающем коде предусмотрите отдельные обработчики обоих типов исключений.
Входные данные / вызов Результат element_at([4,7,9], 3, 3)std::out_of_range -
Цепочка вычислений
Реализовать функции деления и вычисления \(\sqrt{a/b}\). Первая функция генерирует исключение при нулевом знаменателе, вторая — при отрицательном частном. Перехватывать исключения следует только на границе программы.
Требуемая сигнатура:
double safe_divide(double numerator, double denominator); double ratio_sqrt(double numerator, double denominator);Требования:
- Не помещайте
try/catchвнутрь вычислительных функций без необходимости.
Входные данные / вызов Результат ratio_sqrt(8, 2)2ratio_sqrt(1, 0)std::invalid_argument - Не помещайте
-
Геометрия и пользовательские исключения
Написать программу для вычисления площади треугольника по формуле Герона.
- Создать функцию double triangle_area(double a, double b, double c).
- Внутри функции проверить два условия:
- Все стороны должны быть строго больше нуля.
- Должно выполняться неравенство треугольника (сумма любых двух сторон больше третьей).
- Если условия нарушены, сгенерировать пользовательское исключение (структуру),
struct triangle_error { double a, b, c; const char* message; };которое содержит:- Значения сторон a, b, c.
- Текстовое сообщение (const char*) с причиной ошибки.
- Чтобы передавать не только текст, но и контекст ошибки, используем throw следующим образом:
throw triangle_error{3.0, 4.9, -5.0, "Отрицательная сторона"};
- В main организовать цикл while, чтобы пользователь мог вводить данные до тех пор, пока не введет корректные значения (обработать исключения в catch).
- Рациональные дроби (Комплексное задание)
Создать структуру Fraction (Дробь), содержащую числитель (num) и знаменатель (den).
- Написать функцию сложения двух дробей: \( \frac{a}{b}+\frac{c}{d}=\frac{ad+cb}{bd} \)
- Написать функцию, которая принимает массив дробей и их размер, и находит сумму всех дробей в массиве.
- Обработка исключений:
- При создании/передаче дроби, если знаменатель равен 0, выбрасывать исключение.
- При работе с массивом, если передан размер <= 0, выбрасывать исключение.
- Продемонстрировать работу: создать массив из 3-х дробей (одну из них сделать "некорректной" со знаменателем 0). Перехватить ошибку, вывести её, и показать, что программа не "падает", а корректно завершает работу.
Домашнее задание
-
Квадратное уравнение с исключениями
Переписать решение квадратного уравнения так, чтобы вырожденное уравнение и отсутствие действительных корней сообщались разными стандартными исключениями.
Требуемая сигнатура:
std::pair<double, double> quadratic_roots(double a, double b, double c);Требования:
- Один действительный корень вернуть дважды.
- Перехват и печать сообщения выполняются в
main.
-
Изменение массива без частичного результата
Прибавить к каждому элементу массива заданное число, но только если все результаты остаются в диапазоне
[minimum, maximum]. Иначе сгенерировать исключение и оставить массив без изменений.Требуемая сигнатура:
void shift_checked(int* data, int size, int delta, int minimum, int maximum);Требования:
- Сначала полностью проверьте возможность операции, затем изменяйте элементы.
Входные данные / вызов Результат [2,4,7], delta=3, range=[0,9]std::out_of_range; массив [2,4,7] -
Проверка матричных индексов
Реализовать чтение и изменение элемента статической матрицы с проверкой номера строки и столбца.
Требуемая сигнатура:
constexpr int COLS = 4; int get(const int matrix[][COLS], int rows, int row, int column); void set(int matrix[][COLS], int rows, int row, int column, int value);Требования:
- При неверной координате сгенерируйте
std::out_of_rangeс понятным сообщением.
- При неверной координате сгенерируйте