Таким образом, путь для выделения исключений в С++ с помощью std::nested_exception
:
void foo() {
try {
// code that might throw
std::ifstream file("nonexistent.file");
file.exceptions(std::ios_base::failbit);
}
catch(...) {
std::throw_with_nested(std::runtime_error("foo failed"));
}
}
Но в этом методе используются явные блоки try/catch на каждом уровне, где вы хотите вложить исключения, что, по меньшей мере, уродливо.
RAII, который Джон Калб расширяет, поскольку "получение ответственности - это инициализация", - это гораздо более чистый способ борьбы с исключениями вместо использования явной попытки/блоки catch. С RAII явные блоки try/catch в основном используются, чтобы в конечном счете обрабатывать исключение, например. чтобы отобразить сообщение об ошибке пользователю.
Посмотрев на приведенный выше код, мне кажется, что ввод foo()
можно рассматривать как несущий ответственность сообщать обо всех исключениях как std::runtime_error("foo failed")
и вставлять детали внутри nested_exception. Если мы сможем использовать RAII для получения этой ответственности, код выглядит намного чище:
void foo() {
Throw_with_nested on_error("foo failed");
// code that might throw
std::ifstream file("nonexistent.file");
file.exceptions(std::ios_base::failbit);
}
Можно ли использовать синтаксис RAII здесь для замены явных блоков try/catch?
Для этого нам нужен тип, который, когда вызывается его деструктор, проверяет, не вызывает ли вызов деструктора исключение, устанавливает это исключение, если это так, и генерирует новое вложенное исключение, так что разматывание продолжается нормально. Это может выглядеть так:
struct Throw_with_nested {
const char *msg;
Throw_with_nested(const char *error_message) : msg(error_message) {}
~Throw_with_nested() {
if (std::uncaught_exception()) {
std::throw_with_nested(std::runtime_error(msg));
}
}
};
Однако std::throw_with_nested()
требует, чтобы активное событие, обработанное в настоящее время, было активным, что означает, что он не работает, кроме как внутри контекстного блока catch. Поэтому нам нужно что-то вроде:
~Throw_with_nested() {
if (std::uncaught_exception()) {
try {
rethrow_uncaught_exception();
}
catch(...) {
std::throw_with_nested(std::runtime_error(msg));
}
}
}
К сожалению, насколько мне известно, в С++ нет ничего подобного rethrow_uncaught_excpetion()
.