关于析构函数的问题

kingstarer 2009-04-20 08:44:55
网上说析构函数是不允许抛出异常的 那如果需要在析构函数里面调用有可能未知抛出异常的函数(不确定类型,也不知道如何处理)怎么办呢?


顺便问下:
 
try {} catch(...) { /* 在这里面怎么知道什么异常被抛出了呢? */} 
...全文
119 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
kingstarer 2009-04-23
  • 打赏
  • 举报
回复
谢谢各位回答:)
Jinhao 2009-04-20
  • 打赏
  • 举报
回复
不怎么办,如果catch(...)捕捉到的异常,你可以完全当作没发生,或者用一种通用的错误处理方法.
捕捉这样的异常仅仅是为了保证你的类的析构函数是异常安全的.
ryfdizuo 2009-04-20
  • 打赏
  • 举报
回复
建议重新设计一下吧、
老邓 2009-04-20
  • 打赏
  • 举报
回复
catch(...)里根本就不应该再调用函数!
kingstarer 2009-04-20
  • 打赏
  • 举报
回复
因为析构函数里面要调用一个函数去释放资源 但是释放资源过程中有可能出现异常
  • 打赏
  • 举报
回复
[Quote=引用楼主 kingstarer 的帖子:]
网上说析构函数是不允许抛出异常的 那如果需要在析构函数里面调用有可能未知抛出异常的函数(不确定类型,也不知道如何处理)怎么办呢?


顺便问下:

C/C++ code
try {} catch(...) { /* 在这里面怎么知道什么异常被抛出了呢? */} 
[/Quote]

很奇怪,为何异常的接收要放到析构函数里面?
hai040 2009-04-20
  • 打赏
  • 举报
回复
函数是谁提供的
如果真的对异常一无所知的话
也只能打印unknown error了
pengzhixi 2009-04-20
  • 打赏
  • 举报
回复
析构函数抛出异常可能导致资源没法释放.至于解决办法还要等高人来讲解了.
coverallwangp 2009-04-20
  • 打赏
  • 举报
回复
catch(Exception e)
{
e.what();//获得异常信息
}
lingyin55 2009-04-20
  • 打赏
  • 举报
回复


假如目标代码抛出了异常,如果该代码段中某对象的析构函数里也有抛出异常的代码,那么,旧异常的catch块还没有执行的时候,新的异常就被抛出。按标准,当一个异常处理后如果还有其他悬而未解的异常,那么此时程序将自动调用C++标准库中的terminate()函数,该函数默认调用abort()函数非正常结束程序,terminate函数的处理代码也可以自己实现。

#include
#include
#include
using namespace std;

void terminator()
{
cout << "uncaught exception!\n";
// abort(); 标准的terminate默认只调用该函数
exit(0);
}

void (*old_terminate) = set_terminate(terminator);

class foo
{
public:
void f()
{
throw string("f");
}
~foo()
{
throw string("~foo"); // 直接或间接(如调用其他函数等)抛出未决异常
}// 没有异常处理代码,即所谓的“逃离了析构函数的异常”
};


int main()
try {
foo a;
a.f(); // 一个异常
} // 另一个, i.e. ~foo
catch (string& s) {
cout << "inside main() catch (...), exception catched: " << s + "\n"; // 不能达到
}

析构函数中如果有异“逃离析构函数的异常”的出现,则多少说明该设计有些失败,原因如上所述,一个程序,动不动就出错退出的话,用户会满意吗?这其中当然还包括由此而引入的内存泄露等问题。

所以从设计原则上来讲,析构函数应杜绝抛出异常(destructors should never emit exceptions),但如果析构函数调用了其他可能会抛出异常的过程,则析构函数自己应该包含处理所有这些子过程可能抛出的异常的代码。


一种不实用的方法,库函数uncaught_exception()在栈回卷(即有未决异常)的时候返回true,可以依此来检测是否已有异常被抛出而且未决,以避免程序非正常退出:

#include
#include
#include
using namespace std;

void terminator()
{
cout << "uncaught exception!\n";
// abort(); 标准的terminate默认只调用该函数
exit(0);
}

void (*old_terminate) = set_terminate(terminator);

class foo
{
enum {something_wrong = 1};
public:
void f()
{
throw string("f");
}
~foo()
{
// 技术上使用uncaught_exception做异常检测,弃车保帅,知其用则可
if(!uncaught_exception() && something_wrong)
throw string("~foo"); // 直接或间接(如调用其他函数等)抛出未决异常
}
};


int main()
try {
foo a;
a.f(); // 一个异常
} // 另一个, i.e. ~foo
catch (string& s) {
cout << "inside main() catch (...), exception catched: " << s + "\n";
}


接下来就是我们的比较“实用”和“正规”的方法:析构函数要包揽所有处理可能在其执行过程中抛出的异常的代码:

#include
#include
#include
using namespace std;

void terminator()
{
cout << "uncaught exception!\n";
// abort(); 标准的terminate默认只调用该函数
exit(0);
}

void (*old_terminate) = set_terminate(terminator);

class foo
{
enum {something_wrong = 1};
public:
void f()
{
throw string("f");
}
~foo()
{
try {
throw string("~foo"); // 直接或间接(如调用其他函数等)抛出未决异常
} catch (string& s) {
cout << "inside main() catch (...), exception catched: " << s + "\n";
}
}
};


int main()
try {
foo a;
a.f(); // 一个异常
} // 另一个, i.e. ~foo
catch (string& s) {
cout << "inside main() catch (...), exception catched: " << s + "\n";
}


关于更加精辟的解说和一些原则性的指引,请参考:
1、Thinking in C++ 2nd ed Vol.2
Part 1: Building Stable Systems

>>> Uncaught exceptions
>>> Exception safety

2、Effective C++ 3rd ed
>>> Item 8: Prevent exceptions from leaving destructors

一些从书里复制来的话:

From Thinking in C++:

>>> a destructor that throws an exception or causes one to be thrown is usually a sign of poor design or sloppy coding.


>>> It turns out to be practically impossible to design exception-safe code without assuming that destructors don’t throw exceptions. Don’t let destructors throw exceptions.

>>> Don’t cause exceptions in destructors
Because destructors are called in the process of throwing other exceptions, you’ll never want to throw an exception in a destructor or cause another exception to be thrown by some action you perform in the destructor. If this happens, a new exception can be thrown before the catch-clause for an existing exception is reached, which will cause a call to terminate( ).

If you call any functions inside a destructor that can throw exceptions, those calls should be within a try block in the destructor, and the destructor must handle all exceptions itself. None must escape from the destructor.

From EC++:

>>> Things to Remember

·Destructors should never emit exceptions. If functions called in a destructor may throw, the destructor should catch any exceptions, then swallow them or terminate the program.

·If class clients need to be able to react to exceptions thrown during an operation, the class should provide a regular (i.e., non-destructor) function that performs the operation.
kingstarer 2009-04-20
  • 打赏
  • 举报
回复
但问题是我根本不知道调用的函数会抛出什么异常,如何处理

目前有个想法是,用catch(...)然后把异常信息打印出来然后就不管

但是不知道 怎么打印catch(...)获得的异常信息

不知道标准的做法是怎么做呢?
coverallwangp 2009-04-20
  • 打赏
  • 举报
回复
可以在析构函数里处理异常,但是不能让析构函数在throw出异常
try
{
}
catch()
{
}

64,654

社区成员

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

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