C++

Domain_error в C++: как спровоцировать и зачем это нужно

std::domain_error — это стандартное исключение C++, которое используют, когда аргумент функции выходит за допустимую область значений. Например, функция ожидает положительное число, а получила отрицательное

Самый прямой способ спровоцировать domain_error — бросить его вручную через throw

#include <stdexcept>

throw std::domain_error("negative value is not allowed");

Но в нормальном коде исключение бросают не просто ради ошибки, а в месте проверки входных данных

Пример с квадратным корнем

Математически квадратный корень из отрицательного числа в вещественных числах не определен. Поэтому можно написать безопасную функцию:

#include <cmath>
#include <iostream>
#include <stdexcept>

double checkedSqrt(double x) {
    if (x < 0) {
        throw std::domain_error("sqrt argument must be non-negative");
    }

    return std::sqrt(x);
}

int main() {
    try {
        std::cout << checkedSqrt(-4) << "\n";
    } catch (const std::domain_error& error) {
        std::cout << "Ошибка: " << error.what() << "\n";
    }

    return 0;
}

Вывод будет похож на:

Ошибка: sqrt argument must be non-negative

Такой пример хорошо показывает смысл domain_error: аргумент не подходит для области определения функции

Почему std::sqrt не всегда бросает domain_error

Важно: стандартная std::sqrt обычно не бросает std::domain_error при отрицательном аргументе. В зависимости от реализации и настроек она может вернуть NaN, установить errno или поднять floating-point exception

Поэтому если вам нужно именно исключение std::domain_error, надежнее сделать проверку самим:

if (x < 0) {
    throw std::domain_error("x must be >= 0");
}

Это особенно удобно в учебных задачах и в коде, где вы хотите явно отлавливать неверные аргументы

Пример с процентом

Допустим, функция принимает процент скидки от 0 до 100:

#include <iostream>
#include <stdexcept>

double applyDiscount(double price, double percent) {
    if (percent < 0 || percent > 100) {
        throw std::domain_error("discount percent must be from 0 to 100");
    }

    return price * (1.0 - percent / 100.0);
}

int main() {
    try {
        std::cout << applyDiscount(1000, 150) << "\n";
    } catch (const std::domain_error& error) {
        std::cout << error.what() << "\n";
    }

    return 0;
}

Здесь 150 не подходит по смыслу, поэтому domain_error уместен

Когда использовать domain_error

Используйте std::domain_error, когда значение имеет неправильную область допустимых значений:

  • отрицательный аргумент там, где допустимы только положительные числа;
  • процент вне диапазона 0-100;
  • номер месяца меньше 1 или больше 12;
  • радиус окружности меньше 0.

Если ошибка связана не с областью значений, а с форматом, файлом, памятью или индексом, может подойти другое исключение

Как использовать в проверочном тесте

Спровоцировать domain_error часто нужно не в основной программе, а в тесте: вы хотите убедиться, что функция правильно реагирует на плохой аргумент

Без тестового фреймворка это можно проверить так:

bool thrown = false;

try {
    checkedSqrt(-1);
} catch (const std::domain_error&) {
    thrown = true;
}

if (!thrown) {
    std::cout << "Тест не пройден\n";
} else {
    std::cout << "Тест пройден\n";
}

Идея простая: передаете значение вне допустимой области и проверяете, что исключение действительно было выброшено. В настоящих проектах для этого обычно используют тестовые фреймворки, но логика остается той же

Частые ошибки

Ждать, что математическая функция сама бросит исключение

Не стоит рассчитывать, что std::sqrt(-1) обязательно даст std::domain_error. Делайте явную проверку, если нужна предсказуемость

Ловить исключение по значению

Лучше ловить по константной ссылке:

catch (const std::domain_error& error)

Так не создается лишняя копия объекта исключения

Бросать domain_error вместо проверки логики

Исключение не должно заменять нормальную валидацию пользовательского ввода во всех местах. Если пользователь постоянно вводит данные, иногда удобнее показать сообщение и попросить повторить ввод

Короткий вывод

Чтобы спровоцировать domain_error в C++, используйте throw std::domain_error(...) внутри проверки аргументов. Это исключение подходит, когда значение не входит в допустимую область для вашей функции

Связанные материалы:

Что почитать дальше по C++

Если нужен общий маршрут по теме, откройте рубрику C++. Для соседних задач пригодятся эти разборы:

Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные

Настройки cookie

0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x