Выдача исключения из конструктора исключения в C ++ - PullRequest
0 голосов
/ 05 октября 2018

Обратите внимание, что этот вопрос связан с генерацией исключения из конструктора класса исключения , а не из какого-либо старого конструктора.Мне не удалось найти повторяющийся вопрос по stackoverflow.

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

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

Пример: Предположим, что я хочу разделить все возможные исключения на два типа: User_Error и Coder_Error.Первый указывает, очевидно, что пользователь сделал что-то, что он не должен был делать, а второй указывает, что какая-то серьезная внутренняя проверка не удалась и что кто-то должен подать отчет об ошибке.Вот (явно упрощенный) набросок:

#include <stdexcept>
#include <string>
...

class Coder_Error : public std::runtime_error
{
public:
    Coder_Error( const std::string& msg ) :
       std::runtime_error( msg + "  Please freak out and file a bug report!" )
    {}
};


class User_Error : public std::runtime_error
{
protected:
    static void check_state() const
    {
        ...  // May rely on static members of this class or other classes.
        if ( validation_failed ) {
            throw Coder_Error( "A useful description of the problem." );
        }
    }

public:
    User_Error( const std::string& msg ) : std::runtime_error( msg )
    {
        check_state();
    }
};

Теперь предположим, что я делаю throw User_Error( "Some useful message." ); в случае, если User_Error::check_state() бросит.Что произойдет?

Интерпретация: Я ожидаю, что объект Coder_Error будет брошен до того, как линия throw in throw User_Error( "Some useful message." ) когда-либо встретится, и поэтому мы ненужно беспокоиться о двух исключениях, возникающих одновременно, или о чем-то подобном.Чтобы быть более точным, я ожидаю, что соответствующие шаги будут происходить в следующем порядке:

  1. User_Error::User_Error будет вызван.

  2. User_Error::check_state будет вызван.

  3. Coder_Error::Coder_Error будет вызван.

  4. Объект Coder_Error, созданный на шаге 3, будет брошен.

  5. Начнется разматывание стека, и обычное выполнение будет остановлено, поэтому выполнение никогда не достигнет точки, в которой оно может throw User_Error, созданное на шаге 1. (IЯ предполагаю, что ошибки не обнаруживаются.)

Это правильно?

1 Ответ

0 голосов
/ 05 октября 2018

Насколько я могу судить, вы правы, что оценка throw User_Error(...) имеет четко определенный результат и не вызывает std::terminate, при условии, что объект Coder_Error перехватывается включающим обработчиком. GCC и Clang оба согласны .

Ваши рассуждения верны для C ++ 14 и ниже.В C ++ 17, из-за обязательного удаления копии, конструктор User_Error вызывается в процессе генерирования исключения, , то есть , когда компилятор уже начал оценивать часть throw и имеетвыделил некоторое место где-то для объекта исключения.Однако, когда конструкция выходит из через второе исключение, компилятор очищает это хранилище и переходит к поиску обработчика для второго исключения.В любом случае, результат, как вы говорите.

Обратите внимание, что std::terminate будет вызван, если конструктор копирования, вызванный во время обработки исключения, выйдет из через anисключение (, т.е. , поскольку объект исключения копируется в обработчик, который ловит по значению) ( см. пример ).Это отличается от ситуации, которую вы описали.

...