Есть ли способ определить тип исключения, даже знаю, что вы поймали исключение с помощью catch?Определяется тип исключения после исключения?
Пример:
try
{
SomeBigFunction();
}
catch(...)
{
//Determine exception type here
}
Есть ли способ определить тип исключения, даже знаю, что вы поймали исключение с помощью catch?Определяется тип исключения после исключения?
Пример:
try
{
SomeBigFunction();
}
catch(...)
{
//Determine exception type here
}
Вы можете actully определить тип внутри улова (...), но это не очень полезно:
#include <iostream>
#include <exception>
class E1 : public std::exception {};
class E2 : public std::exception {};
int main() {
try {
throw E2();
}
catch(...) {
try {
throw;
}
catch(const E1 & e) {
std::cout << "E1\n";
}
catch(const E2 & e) {
std::cout << "E2\n";
}
}
}
Этот метод действительно может быть полезен, если 'try {throw; } '... part находится в функции, которая вызывается в блоке' catch (...) '. – wjl
Этот метод * * действительно полезен. Подумайте о вызове обработчика исключений в 'catch (...)'. Обработчик исключений перебрасывает и определяет тип с помощью этой техники. Это позволяет разделять обычные коды кода от неправильного (исключения) кода. – user23573
No.
Это будет по крайней мере, требуют, чтобы вы могли получить доступ к текущему исключение. Я не верю, что есть стандартный способ сделать это.
Как только у вас был экземпляр исключения, вам придется использовать алгоритм проверки типа. C++ не имеет неотъемлемой поддержки для этого. В лучшем случае вам нужно будет иметь большой оператор if/elseif с dynamic_cast для проверки типа.
Если вам нужно обрабатывать исключения по-разному в зависимости от того, что они есть, вы должны поймать определенные исключения. Если есть группы исключений, все из которых нужно обрабатывать одинаково, то их можно будет вывести из общего базового класса и поймать базовый класс. Используйте силу и парадигмы языка, не сражайтесь с ними!
Короткий ответ: Нет
Длинный ответ:
Если вывести все свои исключения из общего базового типа (скажем, станд :: исключение) и поймать это явно, то вы можете использовать это, чтобы получить тип информацию из вашего исключения.
Но вы должны использовать функцию улова, чтобы поймать как особый тип исключения, а затем работать оттуда.
Единственное реальное использование для улова (...) является:
Отредактировано: Вы можете извлечь информацию о типе через dynamic_cast <>() или через typid() Хотя, как было сказано выше, это не Somthing я рекомендую. Используйте утверждения case.
#include <stdexcept>
#include <iostream>
class X: public std::runtime_error // I use runtime_error a lot
{ // its derived from std::exception
public: // And has an implementation of what()
X(std::string const& msg):
runtime_error(msg)
{}
};
int main()
{
try
{
throw X("Test");
}
catch(std::exception const& e)
{
std::cout << "Message: " << e.what() << "\n";
/*
* Note this is platform/compiler specific
* Your milage may very
*/
std::cout << "Type: " << typeid(e).name() << "\n";
}
}
Как это работает в этом случае с уловом? – JaredPar
Отредактировано, чтобы уточнить, что вам нужно поймать базовое исключение. –
", то вы можете использовать это, чтобы получить информацию о типе из своего исключения.". Как? Через что-то вроде dynamic_cast? –
Если вы используете Visual C++ (управляемый), вы можете использовать GetType(), чтобы получить тип исключения и обработать его оттуда.
E.g.
try
{
// Run the application
Application::Run(mainForm);
}
catch (Exception^ e)
{
String^ exception_type = e->GetType()->ToString();
throw;
}
Строка будет содержать нечто вроде «System.ArgumentOutOfRangeException».
Это не C++. Это C++/CLI. В основном это синтаксис C++ для среды выполнения .NET. Он предлагает функциональность C++, но часть CLI полностью отличается от того, что C++. – Eonil
Я пробовал разные способы; это работает для меня:
Начните подклассов runtime_error:
/*----------------------------------------------------------------------*/
/* subclass runtime_error for safe exceptions in try/throw/catch */
#include <stdexcept>
/* a little preprocessor magic here -- makes a subclass of runtime_error*/
#define NEWERROR(NE) class NE : public runtime_error { \
public: NE (string const& error) : runtime_error(error) {} }
NEWERROR(FileError );
NEWERROR(NetworkError );
NEWERROR(StringError );
NEWERROR(CofeeError );
/*----------------------------------------------------------------------*/
Тогда вы можете создать несколько экземпляров ваших исключений.
/*----------------------------------------------------------------------*/
/* some example pre-defined exceptions */
FileError ReadOnly ("ReadOnly" );
FileError FileNotFound ("FileNotFound" );
NetworkError TimeOutExceeded ("TimeOutExceeded" );
NetworkError HostNotFound ("HostNotFound" );
CoffeeError OutOfCoffee ("OutOfCoffee" );
/*----------------------------------------------------------------------*/
Явное уведомляет компилятор, что функция может вызвать исключение или программу, вероятно, прекратить в точке брошенной, и данные могут быть потеряны или повреждены , если ресурсы используются в то время.
«Убедитесь, что вы можете и можете поймать все, что можете бросить».
(я использую общий runtime_error, потому что бросать и ловить его охватывает все моих исключений плюс те систем, а также.)
/*----------------------------------------------------------------------*/
/* example function that may throw an exception */
#include <fstream>
ifstream& getFileStream (string fname) throw (runtime_error)
{
if (fname == "")
throw StringError("<getFileStream> fname:empty string");
// processing stops here if thrown
try
{
ifstream Inputfstream;
ifstream& ifsref = Inputfstream;
// ifstream has its own <legacy> exception
// mechanisms and procedures
ifsref.exceptions (ifstream::failbit | ifstream::badbit);
ifsref.open (fname , ifstream::in); // could fail ==> ifstream::failure exception
}
catch (ifstream::failure e)
{
throw FileError(fname + string(e.what()));
}
return ifsref;
}
/*----------------------------------------------------------------------*/
то в вашей TRY/улова
/*----------------------------------------------------------------------*/
catch (FileNotFound fnf) //catch a specific error
{
if (DEBUG) cerr << "[File Not Found Error: " << fnf.what() << "]" << endl;
... (handle it) ...
}
catch (FileError fe) //catch a specific type
{
if (DEBUG) cerr << "[File Error: " << fe.what() << "]" << endl;
... (handle it) ...
}
catch (runtime_error re) // catch a generic type
{
if (DEBUG) cerr << "[Runtime error: " << re.what() << "]" << endl;
// determine type by string comparison
if (re.what() == string("ResourceNotavailable")) ...
if (re.what() == string("NetWorkError") ) ...
...
}
catch (...) // catch everything else
{ ... exit, rethrow, or ignore ... }
/*----------------------------------------------------------------------*/
runtime-error класс имеет хорошую поддержку в стандартных библиотеках C++, и компиляторы знают об этом внутренне и о том, как оптимизировать память и отправку, , чтобы вы могли безопасно и уверенно использовать их на разных кодовых базах. Код портативный и совместим со многими различными компиляторами и архитектурами.
Может быть предпочтительнее и несколько быстрее улавливать каждую ошибку отдельно в предложении catch, от более специфичного до более общего, если вы чувствуете, что серия совпадений строк - ужасная трата процессора и памяти (компилятор оптимизирует их, хотя).
<stdexcept>
дает несколько видов исключений в 2-х группах:
Логические ошибки:
logic_error
domain_error
invalid_argument
length_error
out_of_range
ошибки Runtime:
runtime_error
range_error
overflow_error
underflow_error
синтаксис использования для некоторых из них несколько отличается.
Традиционная мудрость в C++ говорит, что ваши исключения должны быть относительно «плоские», означает, что большие иерархии конкретных категорий исключений следует отказаться в пользу коротких общего, но информативных для общих задач программирования. Задачи, специфичные для домена, такие как логика сетевой системы, высшая математика и т. Д., Могут извлечь выгоду из специфики, но это может быть достигнуто с помощью создания интеллектуальных строк ошибок с общими исключениями времени выполнения/логики.
Наконец, Моя точка является: Вы можете достичь всего этого с помощью метания и ловли только runtime_error.
Для каждого класса вам не нужно создавать целый трюк-мешок с особыми исключениями (например, java) для каждой конкретной ошибки.
Хмм .. с указанием типа исключений метод throws был устаревшим на некоторое время. –
Да, так сказано. Но на самом деле есть некоторые проблемы, которые могут быть неочевидны, если не указывать тип исключения. Проблема заключается в том, что на самом деле любой метод может бросать что-либо: int, char *, objects и т. Д. Если вы укажете, какой метод X выбрасывает (A, B, C), а затем он бросает что-то еще (например, ошибку malloc), тогда std :: неожиданно вызывается вместо поиска метода обработчика или вызова std :: terminate. Или если вы просто объявляете метод с пустым предложением throw() std :: неожиданным, вызывается в любом исключении. –
Нет стандартного портативного способа для этого. Вот непереносимой способ сделать это на GCC и лязгом
#include <iostream>
#include <cxxabi.h>
const char* currentExceptionTypeName()
{
int status;
return abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0, 0, &status);
}
int main()
{
try {
throw std::string();
} catch (...) {
std::cout<<"Type of caught exception is "<<currentExceptionTypeName()<<std::endl;
}
return 0;
}
Выход:
Type of caught exception is std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
Этот вопрос был задан вопрос некоторое время назад, и я предлагаю этот ответ в качестве дополнения к принятому ответ от 9 лет назад. Я должен согласиться с этим респондентом, что этот ответ «... не очень полезен». Кроме того, он открывает дверь для исключения, которое когда-то было обработано без обработки. Чтобы проиллюстрировать это, позвольте мне опираться на ответ респондента
#include <iostream>
#include <exception>
class E1 : public std::exception {};
class E2 : public std::exception {};
class E3 : public std::exception {};
int main() {
try {
throw E3();
}
catch(...) {
try {
// OOOPS!!! E3 is now unhandled!!!!!!
throw;
}
catch(const E1 & e) {
std::cout << "E1\n";
}
catch(const E2 & e) {
std::cout << "E2\n";
}
}
}
Альтернативой такому подходу будет следующим:
#include <iostream>
#include <exception>
class E1 : public std::exception {};
class E2 : public std::exception {};
class E3 : public std::exception {};
int main() {
try {
throw E3();
}
catch(const E1 & e) {
std::cout << "E1\n";
}
catch(const E2 & e) {
std::cout << "E2\n";
}
catch(...) {
std::cout << "Catch-all...";
}
}
Этот второй подход, как представляется, равнозначно к первому и имеет преимущество в частности, обрабатывая E1
и E2
, а затем ловить все остальное. Это предлагается только в качестве альтернативы.
Пожалуйста, обратите внимание, что, в соответствии с проектом C++ в 2011-02-28, пункт 15.3, пункт пули 5, «Если присутствует, ... обработчик должен быть последним обработчиком для его Ьги блока.»
может у PLZ объяснить, почему это нужно? возможно, мы можем искать альтернативы? –
Я бы, очевидно, никогда не делал этого с нуля, но при определенных обстоятельствах я под ним был бы полезен. Устаревший код. –