Подтвердить что ты не робот

Определяется тип исключения после исключения?

Есть ли способ определить тип исключения, даже знаю, что вы поймали исключение с помощью catch?

Пример:

try
{
   SomeBigFunction();
}
catch(...)
{
   //Determine exception type here
}
4b9b3361

Ответ 1

Вы можете определить тип внутри 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";
            }
        }
    }

Ответ 2

Короткий ответ: Нет.

Длительный ответ:

Если вы выведите все свои исключения из общего базового типа (например, std:: exception) и поймайте это явно, вы можете использовать это, чтобы получить информацию о типе из вашего исключения.

Но вы должны использовать функцию catch, чтобы поймать как особый тип исключения, а затем работать оттуда.

Единственное реальное использование для catch (...):

  • Поймать: и выбросить исключение (остановить исключение с помощью деструктора).
  • Поймать: зарегистрировать исключение unknwon и повторить бросок.

Отредактировано: Вы можете извлечь информацию о типе через 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";
    }
}

Ответ 3

Если вам нужно обрабатывать исключения по-разному в зависимости от того, что они есть, вы должны поймать определенные исключения. Если есть группы исключений, все из которых нужно обрабатывать одинаково, то их можно будет вывести из общего базового класса и поймать базовый класс. Используйте силу и парадигмы языка, не сражайтесь с ними!

Ответ 4

Нет.

Выполнение этого, по крайней мере, потребует от вас доступа к текущему исключению. Я не верю, что есть стандартный способ сделать это.

Как только у вас появился экземпляр исключения, вам придется использовать алгоритм проверки типа. С++ не имеет неотъемлемой поддержки для этого. В лучшем случае вам нужно будет иметь большой оператор if/elseif с dynamic_cast для проверки типа.

Ответ 5

Нет стандартного, переносного способа сделать это. Здесь нетранспортный способ сделать это на 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> >

Ответ 6

Я пробовал разные способы; это работает для меня:

Начать с помощью подкласса 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) для каждого класса, каждый из которых обрабатывает одну конкретную ошибку.

Ответ 7

Если вы используете Visual С++ (управляемый), вы можете использовать метод GetType(), чтобы получить тип исключения и обработать его оттуда.

например.

try
    {
        // Run the application
        Application::Run(mainForm);
    }
    catch (Exception^ e)
    {
        String^ exception_type = e->GetType()->ToString();
        throw;
    }

Строка будет содержать нечто вроде "System.ArgumentOutOfRangeException".