C ++: нарезка объектов и исключения - PullRequest
0 голосов
/ 18 мая 2018

В одном из интервью меня спросили, почему перехват исключений по значению может быть проблемой, и я ответил, что это может вызвать нарезку объектов.И вот что я нахожу в Интернете, например, здесь: https://www.viva64.com/en/w/v746/

Но сейчас я пытаюсь экспериментировать и не могу найти пример нарезки при ловле по значению.Обычный сценарий нарезки (без исключений) таков:

Derived d1;
Derived d2;
Base& b1 = d1;
Base& b2 = d2;
b1 = b2;

В последней строке вызывается оператор присваивания Base, который копирует только базовую часть производного объекта.Таким образом, основанная часть b1 копируется из d2, в то время как производная часть b1 остается из d2.ПЛОХО.

Но как это может произойти при перехвате исключений по значению?

Я пробовал этот код (с компиляторами g ++ и Sun CC):

struct Base
{
    virtual void print() const
    {
        cout << "{ Base: " << m << " }" << endl;
    }

    Base(int _m = 0) : m(_m) {}

    int m;
};

struct Derived : Base
{
    Derived(int _m = 0, int _n = 0) : Base(_m), n(_n) {}

    void print() const
    {
        cout << "{ Base: " << m << ", Derived: " << n << " }" << endl;
    }

    int n;
};

int main()
{
    try
    {
        try
        {
            throw Derived(3, 300);
        }
        catch(Base x)
        {
            cout << "Inner catch: ";
            x.print();
            throw;
        }
    }
    catch(Derived y)
    {
        cout << "Outer catch: ";
        y.print();
    }    
}

вывод был:

Inner catch: { Base: 3 }
Outer catch: { Base: 3, Derived: 300 }

Так что я выбрасываю исключение Derived, перехватываю его Base BY VALUE и перебрасываю, затем ловлю Derived BY VALUE и все работает нормально, без нарезки.Как это?

А кто-нибудь может привести пример нарезки при ловле по значению?

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Еще одна проблема отлова Exception по значению, это то, что требуется полная копия исключения.Если вы близки к условию StackOverflow (или уже обрабатываете его), вы можете оказаться в ситуации, когда копирование невозможно, а предложение catch не может быть выполнено.

0 голосов
/ 18 мая 2018

Несмотря на то, что catch(Base) делает нарезку брошенного Derived объекта, re throw использует исходный объект исключения вместо нарезанной копии.

С http://en.cppreference.com/w/cpp/language/throw:

Отбрасывает текущее обработанное исключение.Отменяет выполнение текущего блока catch и передает управление следующему подходящему обработчику исключений (но не другому предложению catch после того же блока try: его составной оператор считается «завершенным»), повторное использование существующегообъект исключения : новые объекты не создаются.Эта форма разрешена только в том случае, если в настоящее время обрабатывается исключение (она вызывает std :: terminate, если используется иначе).Предложение catch, связанное с функцией-try-block, должно выйти через повторное бросание, если используется в конструкторе.


Обратите внимание, что если вы замените throw; на throw x;, a Baseэкземпляр будет брошен и не будет перехвачен, в результате чего будет вызван std::abort().Действительно, нарезанный Derived не может быть не нарезанным (именно поэтому мы обычно не любим кусочки, если только они не являются пиццей кусочками), которые можно поймать с помощью catch (Derived).

КакВ заключение, я бы придерживался "Бросок по значению, ловить по (const) ссылке)" .В этом конкретном примере вы хорошо ловите по разрезанному значению, но это не совсем так. Серж Баллеста ответ привести пример улова по значению, приводящего к неприятностям.Быстрый поиск в вашей любимой поисковой системе может помочь вам найти другие случаи, когда при поиске по значению возникают проблемы.

...