Ответ 1
1. Я не знаю, что я назвал бы это идиомой. Если "правильно" означает "что-то похожее на то, как std::vector
является" правильным "контейнером для использования по умолчанию, я не думаю, что действительно существует определенный" правильный "способ обработки ошибок. Это правильный способ в том, что он четко определяет поведение.
2. Сначала вы должны вызвать print_backtrace()
в контексте, который не ограничивается некоторыми исключениями, что означает, что вы должны вызвать его в блоке catch(...)
:
try {
run();
} catch(...) {
print_backtrace();
}
Но тогда у вас нет исключения известного типа для передачи функции. Вместо этого вам нужно написать функцию для доступа к исключению по-разному; путем исключения этого исключения и его локализации (поскольку это единственный механизм, с помощью которого вы можете привязать переменную известного типа к произвольному исключению).
void print_backtrace(int depth = 0) {
try {
throw;
}
// this block shows how to handle exceptions of some known type
// You can have your own types instead of std::exception
catch (const std::exception & e) {
std::cerr << std::string(depth, ' ') << e.what() << std::endl;
try {
std::rethrow_if_nested(e);
}
catch (...) {
print_backtrace(++depth);
}
}
// Not all nesting exceptions will be of a known type, but if they use the
// mixin type std::nested_exception, then we can at least handle them enough to
// get the nested exception:
catch (const std::nested_exception & ne) {
std::cerr << std::string(depth, ' ') << "Unknown nesting exception\n";
try {
ne.rethrow_nested();
}
catch (...) {
print_backtrace(++depth);
}
}
// Exception nesting works through inheritance, which means that if you
// can't inherit from the type, then you can't 'mixin' std::nesting exception.
// If you try something like std::throw_with_nested( int{10} ); Then you'll
// hit this catch block when printing the backtrace.
catch (...) {
std::cerr << std::string(depth, ' ') << "Unknown exception\n";
}
}
3. std::rethrow_exception
используется с std::exception_ptr
, который является типом, который может использоваться для переноса произвольного исключения. Единственный способ получить это исключение - использовать обычный механизм обработки исключений для исключения catch
, что означает, что вы должны иметь возможность выбросить это исключение. То, что делает rethrow_exception
. Это можно использовать для переноса произвольного исключения из одного потока в другой (как это делает std::future
) или для хранения произвольного исключения в качестве члена (как std::nested_exception
) или для передачи произвольного исключения в качестве параметра для которая попытается напечатать некоторое описание исключения.
void print_backtrace(std::exception_ptr e) {
try {
std::rethrow_exception(e);
}
catch (const std::exception & e) {
// ...