Как использовать std :: nested_exception и друзей? - PullRequest
27 голосов
/ 06 декабря 2011

Я заметил, что есть еще несколько интересных объявлений в <exception> в C ++ 11.Кто-нибудь может пролить свет на то, что они имеют в виду и как их использовать?

Я задаюсь вопросом:

  1. ::std::nested_exception
  2. ::std::throw_with_nested
  3. ::std::rethrow_if_nested

Кроме того, хотя они кажутся самоочевидными, было бы неплохо узнать, как они работают:

  1. ::std::exception_ptr
  2. ::std::make_exception_ptr
  3. ::std::current_exception
  4. ::std::rethrow_exception

1 Ответ

24 голосов
/ 06 декабря 2011

Какой-то высокоуровневый код обычно просто перехватывает 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().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...