Есть ли способ определить тип исключения, даже знаю, что вы поймали исключение с помощью catch?
Пример:
try
{
SomeBigFunction();
}
catch(...)
{
//Determine exception type here
}
Есть ли способ определить тип исключения, даже знаю, что вы поймали исключение с помощью catch?
Пример:
try
{
SomeBigFunction();
}
catch(...)
{
//Determine exception type here
}
Вы можете определить тип внутри catch (...), но это не очень полезно:
#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";
}
}
}
Короткий ответ: Нет.
Длительный ответ:
Если вы выведите все свои исключения из общего базового типа (например, std:: exception) и поймайте это явно, вы можете использовать это, чтобы получить информацию о типе из вашего исключения.
Но вы должны использовать функцию catch, чтобы поймать как особый тип исключения, а затем работать оттуда.
Единственное реальное использование для catch (...):
Отредактировано: Вы можете извлечь информацию о типе через dynamic_cast < > () или через typid() Хотя, как указано выше, это не то, что я рекомендую. Используйте утверждения 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";
}
}
Если вам нужно обрабатывать исключения по-разному в зависимости от того, что они есть, вы должны поймать определенные исключения. Если есть группы исключений, все из которых нужно обрабатывать одинаково, то их можно будет вывести из общего базового класса и поймать базовый класс. Используйте силу и парадигмы языка, не сражайтесь с ними!
Нет.
Выполнение этого, по крайней мере, потребует от вас доступа к текущему исключению. Я не верю, что есть стандартный способ сделать это.
Как только у вас появился экземпляр исключения, вам придется использовать алгоритм проверки типа. С++ не имеет неотъемлемой поддержки для этого. В лучшем случае вам нужно будет иметь большой оператор if/elseif с dynamic_cast для проверки типа.
Нет стандартного, переносного способа сделать это. Здесь нетранспортный способ сделать это на GCC и clang
#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> >
Я пробовал разные способы; это работает для меня:
Начать с помощью подкласса 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
/*----------------------------------------------------------------------*/
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 имеет хорошую поддержку в стандартных библиотеках С++, и компиляторы знают об этом внутренне, и как оптимизировать память и отправку, поэтому вы можете безопасно и уверенно использовать их на разных кодовых базах. Код портативный и совместим со многими различными компиляторами и архитектурами.
Может быть предпочтительнее и несколько быстрее поймать каждую ошибку отдельно в предложении catch, от более конкретного до более общего, если вы чувствуете, что серия совпадений строк - это ужасная трата процессора и памяти (компилятор их оптимизирует),
<stdexcept>
дает несколько видов исключений в двух группах:
Логические ошибки:
logic_error
domain_error
invalid_argument
length_error
out_of_range
Ошибки времени выполнения:
runtime_error
range_error
overflow_error
underflow_error
Синтаксис использования для некоторых из них несколько отличается.
Традиционная мудрость в С++ говорит, что ваши исключения должны быть относительно "плоскими", что означает, что большие иерархии конкретных категорий исключений следует избегать в пользу коротких, но информативных для общих задач программирования. Задачи, специфичные для домена, такие как логика сетевой системы, высшая математика и т.д., Могут извлечь выгоду из специфики, но это может быть достигнуто с помощью создания интеллектуальных строк ошибок с общими исключениями времени выполнения/логики.
Наконец, Моя точка: вы можете достичь всего этого бросать и ловить только runtime_error.
Вам не нужно создавать целую сумку с особыми исключениями (например, java) для каждого класса, каждый из которых обрабатывает одну конкретную ошибку.
Если вы используете Visual С++ (управляемый), вы можете использовать метод GetType(), чтобы получить тип исключения и обработать его оттуда.
например.
try
{
// Run the application
Application::Run(mainForm);
}
catch (Exception^ e)
{
String^ exception_type = e->GetType()->ToString();
throw;
}
Строка будет содержать нечто вроде "System.ArgumentOutOfRangeException".