Должны ли исключения быть связаны в C ++? [duplicate]

10
задан Raedwald 22 November 2017 в 14:47
поделиться

3 ответа

Необходимо скопировать данные из объекта исключения в цепочку, если вы хотите, чтобы они пережили блок catch , который их получает, кроме повторного выброса бросок; . (Что включает, например, если этот блок catch выходит через объект throw ; .)

Это можно сделать, поместив данные для сохранения в куче и реализовав Например, swap ( move в C ++ 0x) на ваши личные данные внутри исключения.

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

struct exception_data { // abstract base class; may contain anything
    virtual ~exception_data() {}
};

struct chained_exception : std::exception {
    chained_exception( std::string const &s, exception_data *d = NULL )
        : data(d), descr(s) {
        try {
            link = new chained_exception;
            throw;
        } catch ( chained_exception &prev ) {
            swap( *link, prev );
        } // catch std::bad_alloc somehow...
    }

    friend void swap( chained_exception &lhs, chained_exception &rhs ) {
        std::swap( lhs.link, rhs.link );
        std::swap( lhs.data, rhs.data );
        swap( lhs.descr, rhs.descr );
    }

    virtual char const *what() const throw() { return descr.c_str(); }

    virtual ~chained_exception() throw() {
        if ( link && link->link ) delete link; // do not delete terminator
        delete data;
    }

    chained_exception *link; // always on heap
    exception_data *data; // always on heap
    std::string descr; // keeps data on heap

private:
    chained_exception() : link(), data() {}
    friend int main();
};

void f() {
    try {
        throw chained_exception( "humbug!" );
    } catch ( std::exception & ) {
        try {
            throw chained_exception( "bah" );
        } catch ( chained_exception &e ) {
            chained_exception *ep = &e;
            for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
                std::cerr << ep->what() << std::endl;
            }
        }
    }

    try {
        throw chained_exception( "meh!" );
    } catch ( chained_exception &e ) {
        for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
            std::cerr << ep->what() << std::endl;
        }
    }
}

int main() try {
    throw chained_exception(); // create dummy end-of-chain
} catch( chained_exception & ) {
    // body of main goes here
    f();
}

вывод (соответственно сварливый):

bah
humbug!
meh!
1
ответ дан 4 December 2019 в 03:14
поделиться

Возможно, вы захотите взглянуть на это: http://www.boost.org/doc/libs/1_43_0/libs/exception/doc/boost-exception.html

Это несколько иной подход, чем тот, что MS сделала в C#, но, похоже, он соответствует вашим требованиям.

1
ответ дан 4 December 2019 в 03:14
поделиться

Другая идея - добавить соответствующие данные в объект исключения, а затем использовать голый оператор throw; для повторного вызова. Я думаю, что в этом случае информация о стеке сохраняется, и вы все равно будете знать первоначальный источник исключения, но тестирование было бы хорошей идеей.

Готов поспорить, что поскольку наличие или отсутствие информации о стеке вообще определяется реализацией, то реализации будут еще больше различаться в том, сохраняется ли она каким-либо образом после простого throw; оператора.

0
ответ дан 4 December 2019 в 03:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: