Работа с ошибками в С++. Деление на ноль

359
31 июля 2017, 13:32

Пишу свой проект в учебных целях для работы с обыкновенными дробями.

#include <iostream>
#include "simple_math.h"
using namespace std;
using namespace simple_math;
int main()
{
    cout << fraction(1, 2) + fraction(1, 3); // в результате выводит "5 / 6"
    return 0;
}

Что если знаменатель какой-то дроби будет равен нулю. Понятно, что нужно выкинуть ошибку, но как это сделать?

if(b == 0)
{
    // ОШИБКА!
}
Answer 1

Если вы хотите работать по C++'ному, то нужно генерировать исключение. Можно собственного типа, можно наследовать от стандартного exception - это уже вопрос стиля и предпочтений. Примерно так -

class DivideByZero {};
...
if (b == 0) throw DivideByZero();
...
try {
    cout << fraction(1, 2) + fraction(1, 3); // в результате выводит "5 / 6"
} catch(DivideByZero&)
{
    cerr << "Divide by zero error!\n"
}

Или, если воспользоваться стандартным - думаю, тут правильнее invalid_argument - то

if (b == 0) throw invalid_argument("Divide by zero error in fraction!");
...
try {
    cout << fraction(1, 2) + fraction(1, 3); // в результате выводит "5 / 6"
} catch(exception&e)
{
    cerr << e.what() << endl;
}
Answer 2

Если вас волнует производительность - учтите, что процессор сам умеет швырять такие исключения при делении на 0, однако, в стандарте C++ такой обработки нет - ее надо сделать:

GCC

#include <signal.h>
#include <memory>
int main() {
    std::shared_ptr<void(int)> handler(
        signal(SIGFPE, [](int signum) {throw std::logic_error("FPE"); }),
        [](__sighandler_t f) { signal(SIGFPE, f); });
    int i = 0;
    cin >> i;  // what if someone enters zero?
    try {
        i = 5/i;
    }
    catch (std::logic_error e) {
        std::cerr << e.what();
    }
}

Visual C++

#include <eh.h>
#include <memory>
int main() {
    std::shared_ptr<void(unsigned, EXCEPTION_POINTERS*)> handler(
        _set_se_translator([](unsigned u, EXCEPTION_POINTERS* p) {
            switch(u) {
                case FLT_DIVIDE_BY_ZERO:
                    throw std::logic_error("Divide by zero");
                ...
                default:
                    throw std::logic_error("SEH exception");
            }
        }),
        [](_se_translator_function f) { _set_se_translator(f); });
    int i = 0;
    try {
        i = 5 / i;
    } catch(std::logic_error e) {
        std::cerr << e.what();
    }
}

Оригинал на enSO

Почему это лучше сравнения с 0 перед делением?

  • это задействует аппаратные возможности платформы по отлову ошибок
  • работает быстрее (не надо делать лишних сравнений)
  • гарантирует, что вы не забудете где-то сделать проверку
READ ALSO
Не работает ofstream

Не работает ofstream

Вот код:

281
Slick slider в модальном окне

Slick slider в модальном окне

Имеется два слайдера slick: один основной для показа товара, второй слайдер ниже с навигационными плитками thumbnail снизу (те

778
Ajax - послать запрос от определенного URL

Ajax - послать запрос от определенного URL

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

248
Запрос по нескольким интервалам

Запрос по нескольким интервалам

Дана таблица id | name | datetimeСуществует ли возможность сделать запрос с подсчётом количества name по нескольким интервалам времени? Например за сутки...

334