Как можно выполнить dynamic_cast из std :: exception в std :: nested_exception? - PullRequest
0 голосов
/ 25 апреля 2018

Я только что видел код, содержащий dynamic_cast от std::exception до std::nested_exception, например,

try {
    std::throw_with_nested(std::runtime_error("error"));
} catch (std::exception &e) {
    auto &nested = dynamic_cast<std::nested_exception&>(e);
    std::cout << "ok" << std::endl;
}

В первый раз я подумал, что этот код не будет скомпилирован, потому что std::nested_exception это не получено из std::exception, и я ожидал, что dynamic_cast сделает статическую проверку наследования, но я ошибся.

Хотя я не смог найти соответствующую стандартную спецификацию, в которой явно упоминаетсячто dynamic_cast позволяет это, я подтвердил, что все три основных компилятора (clang / gcc / msvc) допускают dynamic_cast между совершенно не связанными типами.

Но все же, std::nested_exception не является производным от std::exception,поэтому я подумал, что dynamic_cast выдаст исключение bad_alloc и "ok" никогда не будет напечатано.Я снова был неправ.

Теперь мне интересно, как это может работать.Это что-то особенное и исключительное для std::exception и std::nested_exception?Или я могу сделать еще один успешный dynamic_cast<A&>(b), где тип A и тип объекта b не имеют общего базового класса?

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018

Документация для std :: throw_with_nested гласит, что тип throw будет публично извлечен как из std :: nested_exception , так и из типа передаваемого исключенияв. Итак, в вашем примере исключение, которое выдается концептуально, имеет тип:

class some_exception : public std::nested_exception, public std::runtine_exception
{

};

И, поскольку std::runtime_exception является производным от std_exception, вы можете его перехватить.

0 голосов
/ 25 апреля 2018

В первый раз я подумал, что этот код не будет скомпилирован, потому что std :: nested_exception не является производным от std :: exception

Этого недостаточно - std::nested_exception предназначен для использования в качестве класса mixin, например

struct MyExceptionWrapper: public std::exception, std::nested_exception
{
    // an 3rd-party component of my library threw
    // and I want to wrap it with a common interface
};

ожидал, что dynamic_cast сделает статическую проверку наследования, но я ошибся

В приведенном выше случае dynamic_cast должен проверить во время выполнения , является ли ваш std::exception действительно a MyExceptionWrapper, в этом случае также a std::nested_exception.

Вот почему он называется dynamic cast, потому что он должен проверять динамический тип во время выполнения. Если вы хотите выполнить статическую проверку во время компиляции, вы ищете static cast.

Хотя я не смог найти соответствующую стандартную спецификацию, которая явно упоминает, что dynamic_cast позволяет это

Это все хорошо документировано . Мы обсуждаем следующий пункт со связанной страницы:

  • 5) Если выражение является указателем или ссылкой на полиморфный тип Base, а new_type является указателем или ссылкой на тип Производный, выполняется проверка во время выполнения:

(обратите внимание, что Base=std::exception является полиморфным)

    • b) В противном случае, если выражение указывает / относится к общедоступной базе самого производного объекта и, одновременно, самый производный объект имеет однозначный общедоступный базовый класс типа Derived, результат приведения точек / относится к этому Производное (это называется «sidecast».)

Поскольку вы не можете сказать во время компиляции, что std::exception& на самом деле не MyExceptionWrapper, вы должны сделать это во время выполнения.


PS. если вы хотите избежать случайной переброски внутри блока catch, просто напишите

auto *nested = dynamic_cast<std::nested_exception*>(&e);

вместо этого. Затем вы можете проверить на nullptr, чтобы выяснить, удалось ли это.


PPS. Как предполагает Шон, MyExceptionWrapper выше, скорее всего, будет типом, сгенерированным throw_with_nested, но он имеет тот же эффект.

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