Какой-то высокоуровневый код обычно просто перехватывает std::exception
и печатает what()
. Вы хотите втиснуть как можно больше информации в этот общий механизм, не теряя при этом никакой информации. Рассмотрим реализацию некоторой архивной библиотеки:
archive::archive(const char* filename)
{
ifstream file(filename)
file.exceptions(ios_base::badbit);
open_archive(file); // throws ios_base::failure, or some other low-level exception.
}
Информация, доступная для архива, не записывается (например, имя файла). Кроме того, вы хотели бы отличать исключения, которые пришли из класса архива, от других исключений.
archive::archive(const char* filename)
{
try {
ifstream file(filename)
file.exceptions(ios_base::badbit);
open_archive(file); // throws ios_base::failure, or some other low-level exception.
} catch(const std::exception& e) {
throw archive_exception("Can't open archive", filename, e.what());
}
}
Теперь мы добавили семантическую информацию более высокого уровня, которую знает класс archive
, но мы также потеряли информацию об исходной причине проблемы (тип e
). nested_exception
предназначен для решения этой проблемы:
archive::archive(const char* filename)
{
try {
ifstream file(filename)
file.exceptions(ios_base::badbit);
open_archive(file); // throws ios_base::failure, or some other low-level exception.
} catch(...) {
throw_with_nested(archive_exception("Can't open archive", filename));
}
}
Вся доступная информация записывается. Теперь мы можем получить его в общем виде на сайте улова:
void print_exception_info(const std::exception& e)
{
cerr << e.what() << "\n";
try {
rethrow_if_nested(e);
} catch(const std::exception& ne) {
print_exception_info(ne);
} catch(...) { }
}
int main() {
try {
run();
} catch(const std::exception& e) {
print_exception_info(e);
}
}
Вывод будет более информативным, чем раньше. Он опишет проблему, начиная с высокого уровня до низкого уровня:
Не могу открыть архив "my_archive.bin"
Доступ запрещен.
Или, возможно:
Не удается открыть архив "my_archive.bin"
Запись 'aabb' не найдена.
Функции, работающие с exception_ptr
, предназначены для передачи исключений между потоками или, в более общем случае, для сохранения исключения для последующего использования. Как они работают, зависит от реализации. Предполагалось, что exception_ptr
будет общим указателем на объект исключения. Однако, когда этот указатель создан, при создании исключения или при попытке получить exception_ptr
к нему применяется реализация. Реализация все еще может свободно копировать исключение при вызове current_exception()
.