Вы можете выбрасывать (throw
) или перехватывать (catch
) любые типы С++, которые удовлетворяют некоторым простым требованиям, а именно имеют конструктор копирования и деструктор. Однако исключения являются сложными объектами, поэтому при проектировании класса, который представляет исключительные ситуации, необходимо рассмотреть ряд вопросов. Пример 9.1 показывает, каким может быть простой класс исключения.
#include
#include
using namespace std;
class Exception {
public:
Exception(const string& msg) : msg_(msg) {}
~Exception() {}
string getMessage() const {return(msg_);}
private:
string msg_;
};
void f() {
throw(Exception("Mr. Sulu"));
}
int main() {
try {
f();
} catch(Exception& e) {
cout << "You threw an exception: " << e.getMessage() << endl;
}
}
В языке C++ поддержка исключений обеспечивается при помощи трех ключевых слов: try
, catch
и throw
. Они имеют следующий синтаксис.
try {
// Что-нибудь, что может вызвать функцию "throw", например:
throw(Exception("Uh-oh"));
} catch(Exception& e) {
// Какие-нибудь полезные действия с объектом исключения е
}
Исключение в C++ (аналогично в Java и С#) - это способ, позволяющий поместить сообщение в бутылку, выбросить ее за борт и надеяться, что кто-нибудь пытается найти ваше сообщение где-нибудь ниже по стеку вызовов. Это является альтернативой другим, более простым методам, когда, например, возвращается код ошибки или выдается сообщение об ошибке. Семантика использования исключений (например, «попытка выполнения» каких-то действий, «выбрасывание» исключения с последующим его «перехватом») отличается от других операций С++, поэтому перед описанием способа создания класса исключения я кратко отвечу на вопрос, что представляет собой исключение и что значит выбросить и перехватить его.
Когда возникает исключительная ситуация и вы полагаете, что вызывающая программа должна быть осведомлена об этом, можете «поместить ваше сообщение в бутылку» в операторе throw
, как показано ниже.
throw(Exception("Something went wrong"));
В результате среда времени выполнения сконструирует объект Exception
(исключение), и затем начинается раскрутка стека вызовов до тех пор, пока не найдется блок try
, в который был сделан вход, но из которого еще не сделан выход. Если среда времени выполнения не найдет такой блок, т.е. достигнет функции main
(или верхний уровень текущего потока вычислений), и не может дальше раскручивать стек вызовов, вызывается специальная глобальная функция terminate
. Но если блок try
найден, то просматривается каждый оператор catch
для данного блока try
и находится тот, который перехватывает тип исключения, который был только что выброшен. Подойдет оператор примерно такого вида.
catch(Exception& е) { //...
В этом месте на основе выброшенного исключения создается новый объект Exception
с помощью конструктора копирования класса Exception
. (Объект исключения в области видимости throw
является временным и может быть удален компилятором при оптимизации.) Первоначальное исключение уничтожается, поскольку осуществлен выход из диапазона его видимости и выполняется тело оператора catch
.
Если, находясь в теле оператора catch
, вы хотите только что перехваченное исключение передать дальше, вы можете вызвать функцию throw
без аргументов.
throw;
Это приведет к тому, что процесс обработки исключения будет продолжен на следующие уровни стека вызовов, пока не будет найден другой подходящий обработчик. Это позволяет каждой области видимости перехватывать исключение, выполнять какие-то полезные действия и затем повторно выбрасывать исключение после завершения (или незавершения) таких действий.
Вышесказанное представляет собой ускоренный курс описания процессов выбрасывания и перехвата исключений. Теперь, когда вы обладаете этой информацией, давайте рассмотрим пример 9.1. Вы можете сконструировать исключение Exception
, содержащее указатель символьной строки или строку string
, и затем выбрасывать его. Но такой класс не очень полезен, так как он мало чем отличается от класса-оболочки текстового сообщения. Собственно говоря, вы могли бы получить почти такой же результат, используя в качестве объекта исключения просто строку string
.
try {
throw(string("Something went wrong!"));
} catch (string& s) {