Я проверяю, как выбрасывать при выполнении вызовов раскрутки стека std::terminate
имея конструктор копирования класса, который используется для броска, броска.
Согласно C ++ 14 N4296 — §15.1.3:
Вызов исключительной копии инициализирует (8.5, 12.8) временный объект,
называется объектом исключения. Временный является lvalue и используется для
инициализировать переменную, объявленную в соответствующем обработчике (15.3).
class X
{
public:
X() = default;
X(const X&)
{
throw std::runtime_error{"X copy constructor"};
}
};
int main()
{
try
{
throw X{};
}
catch(const std::exception& e)
{
std::cout << e.what() << std::endl; // this line gets executed, does not terminate
}
catch(const X& other)
{
std::cout << "X exception" << std::endl;
}
}
Почему вышеприведенный код не вызывает std::terminate
? В моем понимании приведенного выше кода throw X{}
внутри try
, запускает перемотку стека, а затем вызывается конструктор копирования для вызова обработчика, но также выдает конструктор копирования. Как примечание, если измените выражение броска конструктора копирования для throw X{}
тогда это заканчивается.
Пока объект исключения не был инициализирован, исключение еще не было выдано. И, таким образом, система не начала выполнять обработку исключений.
Поскольку копия выбрасывает, и это то, что инициализирует объект исключения, единственным throw
который успешно выполняется — тот, что в конструкторе копирования.
Как примечание, если изменить выражение throw конструктора копирования на throw X {}, то оно завершается.
Это фактически переполнение стека из-за бесконечной рекурсии. Каждая попытка создания объекта исключения вызывает еще одно исключение и еще одну попытку создания объекта исключения.
Других решений пока нет …