Как я могу выполнять разные перехваты в зависимости от того, с какой стороны я нахожусь вне границ?

#c #exception #try-catch

#c #исключение #попробуйте-перехват

Вопрос:

Я перегрузил оператор таким образом, что могу возвращать значение массива. Я могу обрабатывать выход за пределы с помощью if :

 float arr::operator[](const int i) const
{
    if (i < 0)
    {
        cout << "Outside of array, first entry returned" << endl;
        return value[0];
    }

    else if (i >=size)
    {
        cout << "Outside of array, last entry returned"  << endl;
        return value[size-1];
    }

    else return value[i];
}
  

но я изучаю исключения и блоки try-catch.

Возможно ли создать исключение с другим значением int (например) для выхода за верхние / нижние границы и иметь перехваты, которые выполняют другой код в зависимости от значения этого int?

Я знаю, что здесь это if хорошо работает, но я хочу развить свои знания для использования в более сложных идеях.

Комментарии:

1. Не используйте целые числа. Выбросить тип .

2. Ах да, я рассматривал это, но это кажется неуклюжим? Выбросить значение int для нижележащих границ и строку для вышележащих? Это лучшее решение?

3. Совсем не неуклюжий и мгновенно узнаваемый для любого, кто читает ваш код. Назовите тип правильно, и код почти самодокументируется. У программиста, который видит throw 42; , скорее всего, возникнет момент WTF, за которым последует поиск по коду, пытаясь выяснить, что вы делаете, или тот же момент WTF, за которым последует выбрасывание вашего кода в мусорное ведро. Но если они видят throw lowerbound; , это им о чем-то говорит.

4. Почему вы не выполняете выборку напрямую std::out_of_range ?

5. @raindrop7 Насколько я мог видеть, он не различал low и high, просто это было вне границ.

Ответ №1:

Возможно ли создать исключение с другим значением int (например) для выхода за верхние / нижние границы и иметь перехваты, которые выполняют другой код в зависимости от значения этого int?

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

 const int OutOfBoundsInFront = -1;
const int OutOfBoundsInBack = 1;

float arr::operator[](const int i) const
{
    if (i < 0)
        throw OutOfBoundsInFront;

    if (i >= size)
        throw OutOfBoundsInBack;

    return value[i];
}

...

try
{
    ... = myarr[index];
}
catch (int value)
{
    switch (value)
    {
        case OutOfBoundsInFront:
            //...
            break;

        case OutOfBoundsInBack:
            //...
            break;
    }
}
  

Однако при создании исключения лучше создавать объект вместо простого типа POD. catch блоки имеют дело с типами, а не со значениями. В этом случае вы можете определить разные типы классов для каждого условия, которое вы хотите перехватить. Например:

 #include <stdexcept>

class OutOfBoundsInFront : public std::out_of_range
{
public:
    OutOfBoundsInFront() : std::out_of_range("out of bounds in front") {}
};

class OutOfBoundsInBack : public std::out_of_range
{
public:
    OutOfBoundsInBack() : std::out_of_range("out of bounds in back") {}
};

float arr::operator[](const int i) const
{
    if (i < 0)
        throw OutOfBoundsInFront();

    if (i >= size)
        throw OutOfBoundsInBack();

    return value[i];
}

...

try
{
    ... = myarr[index];
}
catch (const OutOfBoundsInFront amp;)
{
    //...
}
catch (const OutOfBoundsInBack amp;)
{
    //...
}
  

Альтернативно:

 #include <stdexcept>

class OutOfBoundsOnSide : public std::out_of_range
{
public:
    enum WhichSide { InFront, InBack };

    static const char* WhichSideErrorMsg[] = {
        "out of bounds in front",
        "out of bounds in back"
    };

    WhichSide whichSide;

    OutOfBoundsOnSide(WhichSide side) : std::out_of_range(WhichSideErrorMsg[side]), whichSide(side) {}
};

class OutOfBoundsInFront : public OutOfBoundsOnSide
{
public
    OutOfBoundsInFront() : OutOfBoundsOnSide(InFront) {}
};

class OutOfBoundsInBack : public OutOfBoundsOnSide
{
public
    OutOfBoundsInBack() : OutOfBoundsOnSide(InBack) {}
};

float arr::operator[](const int i) const
{
    if (i < 0)
        throw OutOfBoundsInFront();

    if (i >= size)
        throw OutOfBoundsInBack();

    return value[i];
}

...

try
{
    ... = myarr[index];
}
catch (const OutOfBoundsOnSide amp;e)
{
    switch (e.whichSide)
    {
        case InFront:
            //...
            break;

        case InBack:
            //...
            break;
    }
}
  

Комментарии:

1. Эй, кажется, это отличный ответ! Несколько решений усложняются. Я только что многому научился! (Кроме того, ты всегда был моим любимым из Людей Икс 😉 )