学习用于异常处理的terminate()函数

来源:互联网 发布:网易中超数据库 编辑:程序博客网 时间:2024/05/21 08:39

异常处理是一个微妙的问题,你应该尽可能优雅地处理所有异常。要达到这个目的,你需要学习terminate()函数。


terminate()函数在程序抛出一个异常并且异常没有被捕获的时候被调用,像下面这样:

#include 〈exception〉
#include 〈iostream〉

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 〈iostream〉
#include 〈exception〉

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) ;
// . . .
}

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 一个华为账号有两个游戏账号怎么办 加密u盘电脑上打开空怎么办 国网加密u盘电脑打开为空怎么办 足球竞彩软件下架后里面的钱怎么办 竞彩足球提现不到账怎么办 竞彩足球投注后输了怎么办 英雄联盟鼠标箭头右键点不了怎么办 上古卷轴5数值修改错了怎么办 小时候打针把屁股脂肪打扁了怎么办 大繁盛满腹市场2对话时闪退怎么办 月经来了一个月了还不停怎么办 对办公室的异性老师产生好感怎么办 上古卷轴5任务NPC老打我怎么办 1岁半宝宝走路内八字怎么办 最近几个月例假周期都25天怎么办 从pr导出的视频大小不一样怎么办 合作医疗收据丢了不给报销怎么办 沧州新生医院—老人腹胀了该怎么办 内痔疮术后一个月吃了点辣椒怎么办 肛周脓肿手术后大便干怎么办 月经半个月了还没干净怎么办 房东出租违建房不退房租怎么办 上海公租房住满5年后怎么办 监狱对死缓犯人延长转为无期怎么办 手机号码办理的宽带不想要了怎么办 朋友诈骗罪被关看守所了该怎么办 打架被拘留家里有孩子没人看怎么办 刑事拘留满37天给逮捕了怎么办 因打架被拘留十五天释放后会怎么办 犯罪人在拘留所生了小孩怎么办 我申请了进京证更换车辆怎么办 丈夫去世前想把财产留给妻子怎么办 假货中通代收货款发现是假货怎么办 注册志愿者时身份证被使用该怎么办 双眼皮贴贴的皮肤送了怎么办? 满60岁社保末满十五年怎么办 眼角膜少了一块怎么办应该吃什么 左右胸相差一个罩杯左右怎么办 穿一字肩的裙子没有无肩内衣怎么办 农业网柑橘被奄24小时怎么办 钱包被偷了小偷抓到了钱不认怎么办