Этот ответ может быть выше вашего уровня, но я надеюсь, что он по крайней мере дает вам общее представление о том, что происходит, когда возникает исключение. И это, по крайней мере, даст вам некоторые приемлемые условия.
A throw
заявление не является неотложной функцией вызова. Это точка в программе, где построен определенный объект (будь то int
, std::exception
, std::runtime_error
, или любой другого типа объекта).
После того, как объект исключения сконструирован, стопка разматывается. Это важная концепция, и я попытаюсь набросать ее в нескольких словах. Разматывание стека означает, что все функции, которые вы вызывали, пересекаются в обратном порядке, и все объекты, выделенные (в стеке) в этих функциях, разрушаются. Этот процесс продолжается в обратном направлении до тех пор, пока не будет достигнут блок catch
, который улавливает ваш тип исключения (здесь применяются правила разрешения нормальной перегрузки, поэтому возможны конверсии).
Иллюстративный пример:
#include <iostream>
#include <memory>
#include <string>
class my_exception
{
public:
my_exception(const std::string& message) : message(message) {}
const std::string& what() { return message; }
private:
const std::string message;
};
void boo()
{
int local = 5; // local, "automatic storage duration" variable
throw my_exception("boo threw");
}
void bam()
{
int* i = new int(42); // dynamically allocated int, unowned, accessible
std::unique_ptr<int> j(new int(43)); // dynamically allocated int, owned by a smart pointer with automatic storage duration
boo();
delete i;
}
void f()
{
try
{
bam();
}
catch(const my_exception& e)
{
std::cout << e.what();
}
}
int main()
{
f();
}
Процесс, который потеет заключается в следующем:
main
вводится
f()
называется
try
блок вводится
bam()
является с alled
- a
int
динамически выделяется.Создан указатель на int
с именем i
с автоматической продолжительностью хранения (в стеке)
- a
unique_ptr
объект, содержащий указатель на другой динамически выделенный int
.
boo()
int
с автоматическим хранением в строении.
- Объект типа
my_exception
построен и начинается раскручивание штанов.
boo()
остается, и local
разрушается (очистке)
- мы вернулись в
bam()
, а также оставив позади: первый j
деструктор «s называется, которая вызывает delete
на целое число со значением 43
. Затем объект-указатель i
разрушен, но целым числом, на которое он указал, не является delete
. D. У нас есть утечка памяти (утверждение delete i;
никогда не было достигнуто).
- мы вернулись в
f()
, где дружественный catch
ловит наш my_exception
и выводит message
, хотя std::cout
.
Чтобы ответить на ваши вопросы:
1) Нет, более сложный процесс происходит, что в конечном итоге завершается на этапе 12, который может походить вызов функции, но это не так на самом деле.
2) См. Выше.
3) A catch
«получает» объект. Он работает так же, как функциональные перегрузки. Лучший из них выбран. Если нет совпадения, разматывание продолжается. e
ничего не получает. Он может быть сконструирован из того, что выбрано, но для этого требуется, чтобы тип e
имел правильное преобразование/конструктор.
4) Нет. Указывает наследование. Пример:
#include <stdexcept>
class my_exception : public std::exception
{
public:
my_exception(const std::string& message) : std::exception(message) {}
}
Этот my_exception
класс наследует функцию what()
, определенный в std::exception
, поэтому мне не нужно, чтобы определить это сам.
Ваше сообщение предполагает, что вы еще не совсем поняли понятия _type_ (и _class_), _object_ и _variable_. Я бы работал над этим, прежде чем пытаться понять, как работают исключения. –