使用 try {...} __finally {...} 小心 C++ 的重大 BUG !!!

sczyq 2007-12-15 04:24:25
在服务程序中使用这个结构时,会有重大 BUG!!! 绝不是空穴来风

且看:

try
{
/* A */ ....
try
{
/* B */ ADOQuery->Open();
while (!ADOQuery->Eof)
{
/* C */ int n = ADOQuery->FieldByName("FieldName")->AsString;
ADOQuery->Next();
}
}
__finally
{
/* D */ ADOQuery->Close();
}
/* E */ ...
}
__finally
{
/* F */ ...
}

这个次序,一般是 A->B->C->D->E->F 而执行的,即使 C 行出错了

但事实是若 C 行出错了,次序是 A->B->C->F

若改成如下却很正常!

try
{

/* A */ ....


try
{
/* B */ ADOQuery->Open();
while (!ADOQuery->Eof)
{
/* C */ int n = ADOQuery->FieldByName("FieldName")->AsString;
ADOQuery->Next();
}
}
catch (...)
{
}
/* D */ ADOQuery->Close();
/* E */ ...
}
__finally
{
/* F */ ...
}






...全文
981 29 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
tsk 2009-11-13
  • 打赏
  • 举报
回复
学习了
tsk 2009-11-13
  • 打赏
  • 举报
回复
学习了
Light_X 2008-02-18
  • 打赏
  • 举报
回复
:)
mark
pzhuyy 2008-02-16
  • 打赏
  • 举报
回复
路过,看看。
geochway 2007-12-20
  • 打赏
  • 举报
回复
不应该是BUG,看看BORLAND关于try finally的帮助就知道了.
基本原则是,try语句中出现异常,则先执行finally中的语句,
然后再发出异常,所以finally{}之后的语句可能会被这个异
常所跳过.相当于异常是由这个finally{}发出的.



Sometimes you want to ensure that specific parts of an operation are completed, whether or not the operation is interrupted by an exception. For example, when a routine acquires control of a resource, it is often important that the resource be released, regardless of whether the routine terminates normally. In these situations, you can use a try...finally statement.
The following example shows how code that opens and processes a file can ensure that the file is ultimately closed, even if an error occurs during execution.

Reset(F);

try
... // process file F
finally
CloseFile(F);
end;

The syntax of a try...finally statement is

try statementList1 finally statementList2 end

where each statementList is a sequence of statements delimited by semicolons. The try...finally statement executes the statements in statementList1 (the try clause). If statementList1 finishes without raising exceptions, statementList2 (the finally clause) is executed. If an exception is raised during execution of statementList1, control is transferred to statementList2; once statementList
2 finishes executing, the exception is re-raised. If a call to the Exit, Break, or Continue procedure causes control to leave statementList1, statementList2 is automatically executed. Thus the finally clause is always executed, regardless of how the try clause terminates.

If an exception is raised but not handled in the finally clause, that exception is propagated out of the try...finally statement, and any exception already raised in the try clause is lost. The finally clause should therefore handle all locally raised exceptions, so as not to disturb propagation of other exceptions.
controstr 2007-12-20
  • 打赏
  • 举报
回复
这个不是C++的BUG
你可以看一看<<C++ 程序设计语言>>这本书的介绍
sczyq 2007-12-20
  • 打赏
  • 举报
回复
看来,这不是 BUG ,是我理解有问题

真是:听君一言,胜读十年!

显然,我是没有很仔细地理解 finally 的含义,认为 finally 会怎么样处理,只能说 C++ 太宏大!!!

BUG as error!
n27741 2007-12-19
  • 打赏
  • 举报
回复
try catch 嵌套,是有bug的,java里面就没这个问题
laowang2 2007-12-19
  • 打赏
  • 举报
回复
up
chenxidu 2007-12-19
  • 打赏
  • 举报
回复
这个问题,我还没有遇到过,帮顶
ydlchina 2007-12-19
  • 打赏
  • 举报
回复
俺还是觉得是__finally和catch的作用不同引起的,try-catch的作用就是改变程序默认的异常处理方式,由用户
来处理catch(...)捕获了所有的异常,并且程序对异常没做任何处理。他只在有异常产生时才起作用,否则他就不起
任何作用,这就是它与__finally的不同之处,而__finally俺理解为,他的作用是为了保证程序在最后能够运行
某段程序,它是保证程序必须能够运行该段代码。这是俺的理解,也不知俺的理解是否正确,希望有人能给指点
一下,否则,俺会一致这么用下去。
勉励前行 2007-12-18
  • 打赏
  • 举报
回复
典型的 try __finally 用於恢復現場:

DataSet->AfterScroll = NULL ;
DataSet->DisableControls();
try
{
for(DataSet->First();DataSet->Eof;DataSet->Next())
{
sum += DataSet->Fields->Fields[2]->AsInteger ;
....
}
}
__finally
{
DataSet->AfterScroll = DataSetAfterScroll ; //異常後恢復現場,注意異常的傳播路徑,它會回溯執行對應的__finally語句塊。
DataSet->EnableControls();
}
avg = sum / DataSet->RecordCount ; //正常次序執行代碼,注意出了異常這些代碼並不被執行。

編寫異常安全的代碼是困難的,__finally 給我們多了一個選擇,但也多了一個出錯的機會。

勉励前行 2007-12-18
  • 打赏
  • 举报
回复
try
{CODE1... }
--finally
{CODE2...}
CODE3

出了異常CODE3是不被執行的。
如果要出了異常CODE3還是要執行,但又不想用 try catch處理異常,

try
{CODE1... }
--finally
{CODE2...
goto CODE3 ; //這樣吧。
}
CODE3 :

但這樣做了之後,對多層__finally產生的影響就難說了。套用Waiting4you 的代碼

try{
try
{
OutputDebugString("A");
{
try
{
OutputDebugString("B");
throw Exception("error!");
OutputDebugString("C");
}
__finally
{
OutputDebugString("D");
goto TESTGOTO ; //加上這句,再看其執行次序。
}
}
TESTGOTO:
OutputDebugString("E");
}
__finally
{
OutputDebugString("F");
}
OutputDebugString("G");
}
__finally
{
OutputDebugString("H");
}

//加入goto後,執行次序:ABDEFFH , 對於發生異常後,使用多層 __finally 還是比較危險的,容易連自己也搞不懂程序的執行次序了。
//注意__finally 與catch不同,__finally並不會中止異常的傳播,函數中的異常會一直傳播出去。

對於
void fun1()
{
try{ throw exception("");}
__finally
{...}
}
void fun2
{
try{
fun1();
}
__finally
{}
}
當發生異常時又是如何執行,大量使用 __finally 會令人對發生異常後的執行次序抓狂的。也發現不少程序出現異常後最好退出再重來,否則很容易掛掉,BCB的調試過程就是這樣,調試中出現異常最好結束調試,否則容易連BCB都掛掉。

建議少用 __finally , 改為使用 try catch 結構來替換它,因為catch後異常傳播就至此結束,可以清楚地控制異常。
至少在使用__finally時,要記住try__finally是會向上傳播異常,直到被catch 為止,catch處理異常後再返回逐層執行__finally代碼。
纯冰糖 2007-12-18
  • 打赏
  • 举报
回复
学习学习,我很少用到这样嵌套的代码
lc2236 2007-12-18
  • 打赏
  • 举报
回复
没有bug
__finally
{
/* D */ ADOQuery-> Close();
}
若C异常而D这里ADOQuery 又是出错的主体 ,so 再一次发生异常,如果D这里的执行体与C无关应该是对的
JuncoZhan 2007-12-16
  • 打赏
  • 举报
回复
在某本书上看到try语句本来的推荐写法是:
try {
// 定义
try {
// 分配
}
__finally {
// 释放资源
}
}
catch(...) {
// 报告错误
}
不晓得这样会不会有bug?
constantine 2007-12-16
  • 打赏
  • 举报
回复
try 
{

/* A */ ....


try
{
/* B */ ADOQuery-> Open();
while (!ADOQuery-> Eof)
{
/* C */ int n = ADOQuery-> FieldByName("FieldName")-> AsString;
ADOQuery-> Next();
}
}
catch (...)
{
}
/* D */ ADOQuery-> Close();
/* E */ ...
}
__finally
{
/* F */ ...
}



try的嵌套我只用这种,只应为,不能同时使用catch和finally,所以才嵌套一下。所以没遇到lz说的情况。
一般不会搞得太复杂.
vc8fans 2007-12-16
  • 打赏
  • 举报
回复
没错这就是BCB中的硬伤
编译失败 2007-12-16
  • 打赏
  • 举报
回复
没有这回事吧,普通程序这样嵌套是没问题的,也许楼主说的服务程序确实是个BUG,偶没有试过。
myy 2007-12-16
  • 打赏
  • 举报
回复
建议用“飘遥的安吉儿”的写法,try/__finally 里面套 try/catch .

好像在那里看过一篇相关文章,在 bcb 中 try/__finally 和 try/catch 只管到它内部“第一层”的代码...

这个与Delphi不一样,Delphi中 finally 超强的说。
加载更多回复(9)

13,871

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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