c++ exception

aflyinghorse 2006-03-23 10:39:08
如果违反了异常规范,会出现什么样的行为?
看看这个小程序:
#include <iostream>
using namespace std;

class e{};

void foo() throw ()
{
throw 1;
}

void une()
{
cout << "unexpected...";
}

int main()
{
set_unexpected(une);

try{
foo();
}
catch(...)
{
cout << "catch it!";
}
}


在 .net2003下 结果是显示catch it!
在dev-cpp下 会显示unexpected..., 然后出错退出。

大家有什么样的理解?谢谢。

...全文
771 50 打赏 收藏 转发到动态 举报
写回复
用AI写文章
50 条回复
切换为时间正序
请发表友善的回复…
发表回复
guyanhun 2006-03-28
  • 打赏
  • 举报
回复
好帖!
学习!
aflyinghorse 2006-03-28
  • 打赏
  • 举报
回复
如果大家没有别的问题, 我就揭帖了
来者有分 ^_^
aflyinghorse 2006-03-28
  • 打赏
  • 举报
回复
如果是全局对象抛出了异常, 那么程序就无法回头了。所以还是少用全局变量。
ox_thedarkness 2006-03-27
  • 打赏
  • 举报
回复
恩阿,刚才不小心忘了改帖,确切的代码是下面的:

#include <cstdio>
#include <cstdlib>
#include <exception>
using namespace std;

struct Obj{
int _n;
Obj( int n ):_n(n){ printf("Obj( %d )\n", _n ); }
~Obj(){ printf("~Obj( %d )\n", _n ); }
}L(0); // This golbal would not destroy

void foo() throw (){
Obj l(2); // This local destroys in DevCpp, undestroyed in VC
throw 1;
}

void te(){
static int i=0;
printf("%d terminate...\n", ++i );
abort();
}

void outerFunc(){
Obj l(1); // This local might not be destroyed
foo();
}

int main(){
set_terminate(te);
outerFunc();
}
ox_thedarkness 2006-03-27
  • 打赏
  • 举报
回复
下面的代码显示,DevCpp下,terminate 之前不会进行完全的 unwinding。 只有 throw 直接所在的一层的局部变量被析构,更加外层堆栈的局部变量;以及所有全局变量不会被析构。而VC 则完全不unwinding:

struct Local{
int _n;
Local( int n ):_n(n){ printf("Local( %d )\n", _n ); }
~Local(){ printf("~Local( %d )\n", _n ); }
}L(0); // This golbal would not destroy

void foo() throw (){
Local l(2); // This local destroys after throw
throw 1;
}

void te(){
static int i=0;
printf("%d terminate...\n", ++i );
abort();
}

void outerFunc(){
Local l(1); // This local might not be destroyed
foo();
}

int main(){
set_terminate(te);
outerFunc();
}

///////////////////////////////////////////
DevCpp 4.9.9.2 输出:

Obj( 0 )
Obj( 1 )
Obj( 2 )
~Obj( 2 )
1 terminate...

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

可以看到 DevCpp 中只有 throw 所在层的 Obj(2) 被析构,全局的 Obj(0) 以及外层函数中 Obj(1) 都没有被析构。



而 VC 7.1 输出:

Obj( 0 )
Obj( 1 )
Obj( 2 )
1 terminate...

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

三个Obj 都没有被析构。
ox_thedarkness 2006-03-27
  • 打赏
  • 举报
回复
恩,的确是两次terminate

那么看来C++标准说的 set_terminate 提供的 handler 应该结束程序,大概背后的意思是“如果 handler 不结束程序结果是不确定的”。 也就是说,自定义的terminate中应该调用abort才能保证一致行为:


#include <iostream>
using namespace std;

void foo() throw (){
throw 1;
}

void te(){
static int i=0;
cout << ++i << "terminate...\n";
abort();
}

int main(){
set_terminate(te);
foo();
}

大概是两个编译器都设法保证调用 terminate 一定会结束程序,即使自定义terminate中没有结束程序,但是他们实现方式不同?

- - 不过这块感觉上和模版重载决议一样是C++ 黑暗角落的样子...
ox_thedarkness 2006-03-27
  • 打赏
  • 举报
回复
恩,那是那是~~
aflyinghorse 2006-03-27
  • 打赏
  • 举报
回复
我指的是写自己的unexpected函数,就可以让异常更温顺,系统不会崩溃

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <exception>
using namespace std;

struct Obj{
int _n;
Obj( int n ):_n(n){ printf("Obj( %d )\n", _n ); }
~Obj(){ printf("~Obj( %d )\n", _n ); }
}L(0); // This golbal would not destroy

void foo() throw (bad_exception)// 添加bad_exception
{
Obj l(2); // This local destroys in DevCpp, undestroyed in VC
throw 1;
}

void te(){
static int i=0;
printf("%d terminate...\n", ++i );
abort();
}

void outerFunc(){
Obj l(1); // This local might not be destroyed
foo();
}

void myUnexpect() //定义unexpected函数
{
throw;
}
int main(){
set_unexpected(myUnexpect);//设置
set_terminate(te);
try{
outerFunc();
}catch(...){
cout<<"exception caught"<<endl;
}
}


运行结果是:
Obj( 0 )
Obj( 1 )
Obj( 2 )
~Obj( 2 )
~Obj( 1 )
exception caught
~Obj( 0 )
ox_thedarkness 2006-03-27
  • 打赏
  • 举报
回复
- - 楼上是说 nothrow 的函数 throw 了,gcc 会有办法让系统不崩溃? 偶前面那个例子无论 VC 还是 gcc 都会有变量未析构的。
aflyinghorse 2006-03-27
  • 打赏
  • 举报
回复
vc7竟然 在catch异常的情况下 没有 析构局部变量, 这是不是一个大的 bug? 我对vc很失望


不过对于支持C++异常规范的编译器如gcc, CC(unix下的)。写自己的unexpected函数还是可以捕获异常,让系统不至于崩溃的。异常是一种错误处理的方式,对于有些系统直接崩溃可能不能接受,所以可以写自己的unexpected函数 让他无害化。
ox_thedarkness 2006-03-27
  • 打赏
  • 举报
回复
异常被捕获,当然是会析构。 楼主的代码都是异常没有被捕获的情况,结局只有一个——挂掉。

VC7的方案... 怎么说呢,也许是简单一点点。 他不支持除了nothrow以外的声明,所以也当然不必支持 unexpected ,因为无论以此转换出什么异常都抛不出。 对异常规范的唯一支持就是:terminate。

看下面的代码在VC7下执行。 一旦你用nothrow,表面上看你catch了,实际上 unwinding 还是没有完成:


#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <exception>
using namespace std;

struct Obj{
int _n;
Obj( int n ):_n(n){ printf("Obj( %d )\n", _n ); }
~Obj(){ printf("~Obj( %d )\n", _n ); }
}L(0); // This golbal would not destroy

void foo() throw (){
Obj l(2); // This local destroys in DevCpp, undestroyed in VC
throw 1;
}

void te(){
static int i=0;
printf("%d terminate...\n", ++i );
abort();
}

void outerFunc(){
Obj l(1); // This local might not be destroyed
foo();
}

int main(){
set_terminate(te);
try{
outerFunc();
}catch(...){
cout<<"exception caught"<<endl;
}
}

//////////////////////////////
VC7.1 输出

Obj( 0 )
Obj( 1 )
Obj( 2 )
!
~Obj( 0 )

除了由于“正常”退出,全局变量析构之外,其余所有throw 之时局部变量都未析构。

结论是,这东西还是不用为妙.... 内部抛出非法异常,除了能让你写一个 logfile 说:“不好!因为违反异常限定,我挂掉了!”以外,没有什么别的补救办法。
aflyinghorse 2006-03-27
  • 打赏
  • 举报
回复
现在想想vc7对于异常规范的处理虽然没有符合 C++的标准, 但是却很简单有效,
一个 catch(...)就全部搞定了,不管你是否违反规范。

对于C++的标准 要求的 unexpected 函数, 我觉得也就是给那些未预期的异常一个机会,让程序员去选择是 捕获他让程序不崩溃 还是直接退出, vc的一个catch(...)也可以做到。
aflyinghorse 2006-03-27
  • 打赏
  • 举报
回复
如果调用了terminate,那么程序已经无法回头了。如果因为违反异常规范而调用unexpected,那么可以在该函数里抛出一个符合规范的异常,那么会从异常处理器从新搜索,从而该异常被捕获,程序也可以继续运行。或者在unexpected里抛出不符合规范的异常,在规范中声明bad_exception并且在异常处理器中捕获bad_exception,那么程序也可以不崩溃。
aflyinghorse 2006-03-27
  • 打赏
  • 举报
回复
对于未被捕获得异常,是否调用析构函数依实现而定。如果异常被捕获,那么局部对象的析构应该会保证调用的, 我觉得这是资源获取即初始化的基础。

cutenoob 2006-03-26
  • 打赏
  • 举报
回复
低调低调mark
ox_thedarkness 2006-03-26
  • 打赏
  • 举报
回复
嘎?楼上的代码,偶这里在dev_cpp 下一个terminate输出都没有。 - -b 难道是rp?

我觉得,C++的意思是,调用terminate意味着发生最最无法挽回的错误,程序必须立即退出 —— 因为在此时做挽回工作如果再次出错容易造成 terminate 递归... 所以不在乎程序状态了。 - - 说来说去.... 咋没有其他人指点阿...
ox_thedarkness 2006-03-26
  • 打赏
  • 举报
回复
偶 4.9.8.0, 没改编译器设置,楼上的呢?
strangerryf 2006-03-26
  • 打赏
  • 举报
回复
lz最近的代码的确是在gcc两次terminate,vs一次terminate,但最后的出错信息是一样的。楼上dev版本不对?
guyanhun 2006-03-26
  • 打赏
  • 举报
回复
void foo()
{
A a;
throw 1;
}

局部对象,抛出异常的时候应该会调用析构函数的吧 ?
aflyinghorse 2006-03-26
  • 打赏
  • 举报
回复
我的是 4.9.9.2,默认设置
加载更多回复(29)

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧