xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
异常处理是一个微妙的问题,你应该尽可能优雅地处理所有异常。要达到这个目的,你需要学习terminate()函数。
terminate()函数在程序抛出一个异常并且异常没有被捕获的时候被调用,像下面这样:
#include
#include
void on_terminate()
{
std::cout << "terminate() 函数被调用了!" << std::endl;
std::cin.get();
}
int main()
{
// 如果用 vc6,去掉“std::”前缀
std::set_terminate( on_terminate);
throw std::exception();
std::cout << "terminate() 函数没有被调用!" << std::endl;
std::cin.get();
return 0;
}
避免这种情形的方案一开始看起来很简单:
int main()
{
try
{
/* code */
}
catch( std::exception & exc)
{
// 记录到日志,或作其他处理
}
catch(...)
{
// 记录下“unknown exception”
}
return 0;
}
不过,在多线程应用程序中情况变得有点复杂,因为你创建的每个线程都要有上面的(catch)处理过程。
然而terminate()函数在许多其它情况下会被调用,包括:
当你抛出一个异常,并且在它的拷贝构造函数中,另一个异常被抛出。
在堆栈展开的过程中抛出一个异常,此时析构函数抛出一个异常。
当一个静态对象的构造函数或析构函数抛出异常时。
当一个用atexit注册过的函数抛出一个异常时。
当你在代码中写下“throw;”(这意味着重新抛出当前异常),然而并没有当前异常时。
当一个函数抛出一个它的异常说明不允许的异常时
当默认的unexpected()处理过程被调用时
下面的代码演示了上面各种情况下的结果:
#include
#include
void on_terminate()
{ std::cout << "terminate()函数被调用了!" << std::endl;
std::cin.get(); }
//////////////////////////////// [1]
struct custom_exception
{
custom_exception() {}
custom_exception( const custom_exception &)
{ throw std::exception(); }
};
void case_1()
{
try
{ throw custom_exception(); }
catch(...)
{}
}
//////////////////////////////// [2]
struct throw_in_destructor
{
~throw_in_destructor() { throw std::exception(); }
};
void case_2()
{
try
{
throw_in_destructor temp;
throw std::exception();
}
catch(...)
{}
}
//////////////////////////////// [3]
struct static_that_throws
{
static_that_throws() { throw std::exception(); }
};
void case_3()
{
// 注意:用try/catch块包围下面的代码并不起作用
static static_that_throws obj;
}
//////////////////////////////// [4]
void throw_at_exit()
{ throw std::exception(); }
void case_4()
{ atexit( throw_at_exit); }
//////////////////////////////// [5]
void case_5()
{ throw; }
//////////////////////////////// [6]
class custom_6_a {};
class custom_6_b {};
void func_violating_exception_specification_6() throw(std::exception)
{ throw custom_6_a(); }
// 注意:按照我们的例子,在这个函数中我们只应该抛出
// std::exception(在函数func_violating_exception_specification
// 的定义中说明的异常);但我们没有这样做,
// 因此,terminate() 被调用
void on_unexpected()
{ throw custom_6_b(); }
void case_6()
{
std::set_unexpected( on_unexpected);
try
{ func_violating_exception_specification_6(); }
catch(...)
{}
}
//////////////////////////////// [7]
class custom_7 {};
void func_violating_exception_specification_7() throw(std::exception)
{ throw custom_7(); }
void case_7()
{
try
{ func_violating_exception_specification_7(); }
catch(...)
{}
}
int main()
{
std::set_terminate( on_terminate);
// 注意:确保每次仅去掉下面一个调用的注释,
// 以便分析时将每种情况隔离开来
case_1();
// case_2();
// case_3();
// case_4();
// case_5();
// case_6();
// case_7();
return 0;
}
尽管你应该努力避免terminate()函数会被调用的情况,我们还是建议你创建自己的terminate()处理过程。你的处理过程要做的唯一合理的事是记录一条消息到日志中。不管怎样,确保你的日志不会抛出任何异常。
std::ostream& get_log() { /* code */ }
void on_terminate()
{
std::ostream & log = get_log();
// 确保我们不会抛出任何东西!
try
{
log.exceptions( std::ios_base::goodbit);
}
catch (...)
{}
log << "terminate() 被调用了!" << std::endl;
}
int main()
{
std::set_terminate( on_terminate) ;
// . . .
}
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器