Разница между std:: exception и "..."

A:      catch(...)  
B:      catch(std::exception& e)

Вопрос в том, что может A catch, но B не может.

И почему в С++ не вводится универсальное корневое исключение, которое может поймать что-либо.

--- добавлено Извините, я должен был сказать, что я понимаю, что на С++ вы можете выбросить любой тип типа int, но помимо этого, что еще можно выбросить?

Моя проблема в том, что я пытаюсь найти, какое исключение выбрано из кода, которое может быть уловлено A, но не B. Это исключение определенно не является типом типа "int". Это должно быть системное исключение или нарушение памяти. Мне просто интересно, что это может быть.

Ответы

Ответ 1

catch (...) - это так называемый блок "catch all". Он поймает любое исключение С++.

catch(std::exception& e) будет ловить только исключения, полученные из std::exception.

Вот пример исключения, которое будет вызываться с помощью catch-all, но не второй версии:

throw 42;

Это может показаться вам странным, и это так. Важно понять, что все может быть выбрано как исключение С++, а не только exception или вещи, полученные из exception. Как упоминает @bames53 в комментариях, не существует типа исключения root, из которого производятся все исключения, например, на некоторых других языках.

Также важно отметить, что блокировать все блоки очень легко злоупотреблять. На самом деле, как правило, лучше всего предположить, что все блоки catch-all являются программными дефектами. Конечно, в программировании нет "всегда", но это безопасное предположение для начала, когда вы учитесь использовать исключения.

Причина, по которой блоки блокировки - это Evil, объясняется тем, как они обычно используются. Как правило, наивный программист напишет все-таки в попытке поймать любую ошибку программирования, а затем, критически, продолжить, чтобы программа работала так, как будто ничего не произошло. Это катастрофа в ожидании. Состояние программы теперь неопределенно. Что-то, где-то пошло не так. Вы не можете смело игнорировать исключения и продолжать идти, как будто все в порядке. Даже если ваша программа продолжает работать, может быть тонкая куча коррупции где-то, которая будет фальсифицировать вычисления программы или ее выходы. Когда происходят кучи коррупции, лучшее, на что вы, как программист, можете надеяться, - это немедленный сбой. Таким образом, вы можете получить стек вызовов и файл дампа с точки зрения коррупции и найти и исправить проблему. Но когда у вас все в порядке, вы потеряли весь контекст, где происходит это разложение. Почти невозможно найти реальный дефект в вашем коде.


Конечно, существуют действительные и ценные виды использования обработчика catch. Один из наиболее распространенных - написать глобальный обработчик исключений, который затем исключает исключение. Этот глобальный обработчик может инициировать какой-то журнал регистрации ошибок, возможно, путем регистрации самой ошибки или создания нерегулярной программы, которая выполняет регистрацию вне программы сбоя. Повторяя исключение, вы даете делегатам возможность обрабатывать исключения, которые могут быть обработаны, при этом разрешающее исключение не может быть обработано для завершения программы.

Повторить исключение просто. Просто назовите throw без аргумента, например:

catch (...)
{
  // some magic
  throw;
}

Еще одна вещь, о которой следует помнить, заключается в том, что когда вы поймаете исключение, лучше всего поймать ссылку const, а не только ссылку.

Ответ 2

Короткий ответ - это что-либо без std::exception в его (публичной) наследственной иерархии:

#include <exception>
#include <iostream>

int main()
{
    try
    {
        throw false;
    }
    catch(std::exception& e)
    {
        std::cout << "Caught std::exception" << std::endl;
    }
    catch(...)
    {
        std::cout << "Caught something else" << std::endl;
    }

    return 0;
}

Вывод:

Caught something else

Ответ 3

Как насчет int s?

try {
    throw 123;
} catch (std::exception &e) {
    // this won't catch
} catch (...) {
    // this will catch
}