Ответ 1
Некоторые коды высокого уровня в общем случае просто поймают 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));
}
}
Вся доступная информация записывается. Теперь мы можем в целом получить его на сайте catch:
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()
.