C++ 捕获异常后确定异常类型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/561997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Determining exception type after the exception is caught?
提问by Brian R. Bondy
Is there a way to determine the exception type even know you caught the exception with a catch all?
有没有办法确定异常类型,甚至知道你用 catch all 捕获了异常?
Example:
例子:
try
{
SomeBigFunction();
}
catch(...)
{
//Determine exception type here
}
采纳答案by Martin York
You can actully determine type inside a catch(...), but it is not very useful:
您实际上可以在 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";
}
}
}
回答by Martin York
Short Answer: No.
简短的回答:没有。
Long Answer:
长答案:
If you derive all your exceptions from a common base type (say std::exception) and catch this explicitly then you can use this to get type information from your exception.
如果您从一个公共基类型(比如 std::exception)派生所有异常并明确捕获它,那么您可以使用它从您的异常中获取类型信息。
But you should be using the feature of catch to catch as specific type of exception and then working from there.
但是您应该使用 catch 的功能来捕获特定类型的异常,然后从那里开始工作。
The only real use for catch(...) is:
catch(...) 的唯一真正用途是:
- Catch: and throw away exception (stop exception escaping destructor).
- Catch: Log an unknwon exception happend and re-throw.
- 捕获:并抛出异常(停止异常转义析构函数)。
- 捕获:记录发生的未知异常并重新抛出。
Edited: You can extract type information via dynamic_cast<>() or via typid() Though as stated above this is not somthing I recomend. Use the case statements.
编辑:您可以通过 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";
}
}
回答by user697683
There is no standard, portable way to do this. Here's a non-portable way to do it on GCC and clang
没有标准的、可移植的方法来做到这一点。这是在 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;
}
Output:
输出:
Type of caught exception is std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
回答by Harper Shelby
If you need to handle exceptions differently based on what they are, you should be catching specific exceptions. If there are groups of exceptions that all need to be handled identically, deriving them from a common base class and catching the base class would be the way to go. Leverage the power and paradigms of the language, don't fight against them!
如果您需要根据异常情况以不同方式处理异常,则应该捕获特定的异常。如果存在需要以相同方式处理的异常组,则从公共基类派生它们并捕获基类将是可行的方法。利用语言的力量和范式,不要与它们作斗争!
回答by JaredPar
No.
不。
Doing so would at the very least require you to be able to access the current exception. I do not believe there is a standard way of doing this.
这样做至少需要您能够访问当前异常。我不相信有一种标准的方法可以做到这一点。
Once you had the exception instance, you would have to use a type inspection algorithm. C++ doesn't have inherent support for this. At best you would have to have a big if/elseif statement with dynamic_cast's to check the type.
一旦有了异常实例,就必须使用类型检查算法。C++ 对此没有内在的支持。充其量你必须有一个带有 dynamic_cast 的大 if/elseif 语句来检查类型。
回答by user8315449
provided that c++11 available,
前提是 c++11 可用,
bool throwing_func()
{
// something is wrong...
throw char('5');
// ...
return true;
}
void exception_handler(std::exception_ptr _Eptr)
{
try
{
if (_Eptr) {std::rethrow_exception(_Eptr);}
}
catch(int _Xi)
{
std::cout << "int\n";
}
catch(char _Xc)
{
std::cout << "char\n";
}
catch(const std::exception& _Xe)
{
std::cout << "std::exception " << _Xe.what() << "\n";
}
catch (...)
{// develop more catch cases above to avoid what follows
std::cout << "unhandled exception\n";
// grande problema
}
}
int main()
{
try
{
throwing_func();
}
catch(...)
{
//Determine exception type here
exception_handler(std::current_exception());
}
return 0;
}
回答by Chris Reid
I've tried various ways; this works for me:
我尝试了各种方法;这对我有用:
Begin by subclassing runtime_error:
首先继承 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 );
/*----------------------------------------------------------------------*/
Then you may create some instances of your exceptions.
然后,您可以创建一些例外实例。
/*----------------------------------------------------------------------*/
/* some example pre-defined exceptions */
FileError ReadOnly ( "ReadOnly" );
FileError FileNotFound ( "FileNotFound" );
NetworkError TimeOutExceeded ( "TimeOutExceeded" );
NetworkError HostNotFound ( "HostNotFound" );
CoffeeError OutOfCoffee ( "OutOfCoffee" );
/*----------------------------------------------------------------------*/
Explicitly notify the compiler that your function may throw an exception or the program will probably terminate at the point thrown, and data could be lost or corrupted if resources are in use at the time.
明确通知编译器您的函数可能会抛出异常,或者程序可能会在抛出的点处终止,并且如果当时正在使用资源,则数据可能会丢失或损坏。
"Make sure you can and do catch anything that you can throw."
“确保你能抓住任何你能扔的东西。”
(I use the generic runtime_errorbecause throwing and catching it covers all of my exceptions plus the systems' ones as well.)
(我使用通用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;
}
/*----------------------------------------------------------------------*/
then in your try/catch
然后在你的 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 ... }
/*----------------------------------------------------------------------*/
The runtime-errorclass has good support in the c++ standard libraries, and compilers know about it internally, and how to optimize memory and dispatch, so you can use them over different code bases safely and confidently. The code is portable and compatible with many different compilers and architectures.
在运行时错误类在C ++标准库的良好支持,以及编译器知道它的内部,以及如何优化内存和调度,这样你就可以安全放心地使用他们在不同的代码库。该代码是可移植的,并且与许多不同的编译器和体系结构兼容。
It may be preferable and somewhat faster to catch each error separately in a catch clause, from more specific to more generic,if you feel a series of string matches is a terrible waste of cpu and memory (the compiler optimizes these though ).
如果您觉得一系列字符串匹配是对 CPU 和内存的严重浪费(尽管编译器优化了这些),那么在 catch 子句中分别捕获每个错误可能更可取且速度更快,从更具体到更通用。
<stdexcept>
gives you several kinds of exceptions in 2 groups:
<stdexcept>
为您提供 2 组中的几种异常:
Logic errors:
logic_error domain_error invalid_argument length_error out_of_range
Runtime errors:
runtime_error range_error overflow_error underflow_error
逻辑错误:
logic_error domain_error invalid_argument length_error out_of_range
运行时错误:
runtime_error range_error overflow_error underflow_error
usage syntax is slightly different for some of them.
其中一些的用法语法略有不同。
Conventional Wisdom in C++ says that your exceptions should be relatively "flat", meaning that large hierarchies of specific categories of exceptions should be eschewed in favor of short generic but informative ones for general programming tasks. Domain specific tasks like network system logic, higher maths, etc. may benefit from specificity, but that can be achieved handily by making intelligent error strings with generic runtime/logic exceptions.
C++ 中的传统智慧说你的异常应该是相对“扁平的”,这意味着应该避开特定类别异常的大型层次结构,而支持一般编程任务的简短通用但信息丰富的层次结构。网络系统逻辑、高等数学等领域特定任务可能会受益于特殊性,但这可以通过使用通用运行时/逻辑异常制作智能错误字符串来轻松实现。
Lastly, My Point is: You can achieve all of this by throwing and catching only runtime_error.
最后,我的观点是:您可以通过仅抛出和捕获 runtime_error来实现所有这些 。
You don't have to create a whole trick-bag of highly specific exceptions (like java does) for each class, each handling one specific error.
您不必为每个类创建一整套高度特定的异常(如 java 所做的),每个类都处理一个特定的错误。
回答by Andrew Falanga
This question was asked some time ago and I'm offering this answer as a companion to the accepted answer from 9 years ago. I'd have to concur with that respondent that that answer, "... is not very useful." Further, it opens the door to an exception which was once handled being unhandled. To illustrate, let me build upon the respondent's answer
这个问题是前一段时间提出的,我提供这个答案作为 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";
}
}
}
An alternative to this approach would be the following:
这种方法的替代方法如下:
#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...";
}
}
This second approach seems to be tantamount to the first and has the advantage of specifically handling E1
and E2
and then catching everything else. This is offered only as an alternative.
这第二种方法似乎是等同于第一,有专门处理优势E1
和E2
再赶上一切。这仅作为替代提供。
Please note that, according to C++ draft of 2011-02-28, paragraph 15.3, bullet item 5, "If present, a ... handler shall be the last handler for its try block."
请注意,根据 2011-02-28 的 C++ 草案,第 15.3 段,第 5 项,“如果存在,...处理程序应是其 try 块的最后一个处理程序。”
回答by Roderick
If you're using Visual C++ (managed), you can use the GetType() method to get the type of exception and handle it from there.
如果您使用的是 Visual C++(托管),则可以使用 GetType() 方法获取异常类型并从那里处理它。
E.g.
例如
try
{
// Run the application
Application::Run(mainForm);
}
catch (Exception^ e)
{
String^ exception_type = e->GetType()->ToString();
throw;
}
The string will contain something like "System.ArgumentOutOfRangeException".
该字符串将包含类似“System.ArgumentOutOfRangeException”的内容。