有没有办法确定异常类型,甚至知道你用catch all捕获了异常?
示例:
try
{
SomeBigFunction();
}
catch(...)
{
//Determine exception type here
}
答案 0 :(得分:29)
简答:不。
长答案:
如果从公共基类型(比如std :: exception)派生所有异常并明确捕获它,那么您可以使用它来从异常中获取类型信息。
但是你应该使用catch的特性来捕获特定类型的异常,然后从那里开始工作。
catch(...)的唯一真正用途是:
编辑: 您可以通过dynamic_cast<>()或通过typid()提取类型信息 虽然如上所述这不是我推荐的东西。使用案例陈述。
#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";
}
}
答案 1 :(得分:24)
您实际上可以确定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 :(得分:8)
没有标准的,可移植的方式来做到这一点。这是在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> >
答案 3 :(得分:6)
如果您需要根据它们的不同来处理异常,那么您应该捕获特定的异常。如果存在所有需要以相同方式处理的异常组,则从公共基类派生它们并捕获基类将是可行的方法。利用语言的力量和范例,不要与他们作斗争!
答案 4 :(得分:1)
没有。
这样做至少会要求您能够访问当前的异常。我不相信有这样做的标准方法。
一旦有了异常实例,就必须使用类型检查算法。 C ++没有固有的支持。充其量你必须有一个大的if / elseif语句与dynamic_cast's来检查类型。
答案 5 :(得分:0)
我尝试过各种方式;这对我有用:
从子类化 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 类在c ++标准库中得到了很好的支持, 和编译器在内部了解它,以及如何优化内存和调度, 因此,您可以安全,自信地在不同的代码库中使用它们。该代码是可移植的,并与许多不同的编译器和体系结构兼容。
在catch子句中单独捕获每个错误可能更好,也更快一些,从更具体到更通用,如果你觉得一系列字符串匹配是对cpu和内存的可怕浪费(编译器优化了这些) 。
<stdexcept>
在两组中为您提供了几种例外情况:
逻辑错误:
logic_error
domain_error
invalid_argument
length_error
out_of_range
运行时错误:
runtime_error
range_error
overflow_error
underflow_error
其中一些语言的使用语法略有不同。
C ++中的常规智慧说你的例外应该相对“平淡”, 意味着应避免使用特定类别的异常的大型层次结构 赞成短通用但信息丰富的通用编程任务。网络系统逻辑,高等数学等特定领域的任务可能会受益于特异性,但这可以通过使用通用运行时/逻辑异常制作智能错误字符串来轻松实现。
最后,我的观点是:你可以实现所有这一切 仅投掷并捕获runtime_error 。
您不必创建一整套高度特定的异常 (就像java一样)为每个类,每个处理一个特定的错误。
答案 6 :(得分:0)
这个问题前一段时间被问过,我提供这个答案作为9年前接受的答案的伴侣。我必须同意那位受访者的回答,“......不是很有用。”此外,它打开了一个异常的大门,这个异常曾被处理过,未经处理。为了说明,让我以受访者的答案为基础
except
这种方法的替代方案如下:
addCleanup
第二种方法似乎与第一种方法相当,具有专门处理setUp
和TestContextDecorator
然后捕捉其他所有内容的优势。这仅作为替代方案提供。
请注意,根据C ++草案2011-02-28,段落15.3,项目5,“如果存在,...处理程序应该是其try块的最后一个处理程序。“
答案 7 :(得分:0)
前提是c ++ 11可用,
\b\d{3}(\D)\d{2}\1\d{4}\b
答案 8 :(得分:-2)
如果您使用的是Visual C ++(托管),则可以使用GetType()方法获取异常类型并从那里处理它。
E.g。
try
{
// Run the application
Application::Run(mainForm);
}
catch (Exception^ e)
{
String^ exception_type = e->GetType()->ToString();
throw;
}
该字符串将包含类似“System.ArgumentOutOfRangeException”的内容。