I'm looking at some code in an application of ours and came across something a little odd from what I normally do. With exception handling and cleanup, we (as well as many other programmers out there, I'm sure) use a Try/Finally block embedded with a Try/Except block. Now I'm used to the Try/Except inside the Try/Finally like so:
Try
Try
CouldCauseError(X);
Except
HandleError;
end;
Finally
FreeAndNil(x);
end;
but this other block of code is reversed as so:
Try
Try
CouldCauseError(X);
Finally
FreeAndNil(x);
end;
Except
HandleError;
end;
Looking around the web, I'm seeing folks doing this both ways, with no explanation as to why. My question is, does it matter which gets the outside block and which gets the inside block? Or will the except and finally sections get handled no matter which way it is structured? Thanks.
One difference is that try..finally..except is potentially vulnerable to an exception masking situation.
Imagine that an exception occurs in CouldCauseError(). Then imagine that the attempt to FreeAndNIL(X) in the finally causes a further exception. The original exception (quite possibly which lead to the instability leading to the FreeAndNIL() exception) is lost. The except handler is now handling the "downstream" exception that occured after the original one.
try..except..finally avoids this of course and should be preferred for this reason (deal with exceptions as close as possible to their source).
The other way to handle a simple case such as this (a single object being cleaned) is to include the cleanup both in the normal flow and in the exception handler:
try
CouldCauseError(X);
FreeAndNil(x);
except
HandleError;
FreeAndNil(x);
end;
This looks a little scary at first ("I need to be SURE that FreeAndNIL(X) is called, so I HAVE TO HAVE A FINALLY!!") but the only way that the first FreeAndNIL() might not be called is if there is an exception and if there is an exception you are FreeAndNIL()ing as well anyway, and it makes the order of cleanup in the event of an exception a little clearer (in the sense of removing noise that to some extent has to be "filtered" out in order to understand what is going on).
But, I personally do not like it - if you change code in either the exception handler or the normal flow you risk breaking the cleanup behaviour, but depending on the code around such a block, and the size of the block itself, the reduction in "noise" can be argued to be justified in some cases, for the sake of simplification.
However, this relies on the fact that FreeAndNIL() is actually "NILThenFree()"... X is NIL'd before it is Free'd, so if an exception occurs in the FreeAndNIL(X) in the normal flow, then X will be NIL when the exception handler catches the exception raised by X.Free, so it will not attempt to "double-free" X.
Whatever you decide, I hope that helps.
The finally and except will both trigger, the order is up to you. It depends on what you want to do in your finally or except block. Do you want to free something that is used in the except block? Place finally around the except block.
It all depends if the code in your finally block can raise an exception itself (then it needs to be protected by an upper level try except), or if you need something in your exception handling that should be freed later (then it needs to be freed in an upper level finally block).
All that means that sometimes you can even have some code like:
try
try
try
CouldCauseError(X);
except
HandleErrorWith(X);
end;
finally
FreeAndNil(X); // and/or any resource cleanup
end;
except
CatchAllError;
end;
At first your code looks a little bit strange. I miss the creation of X.
X := CreateAnX
try
DoSomeThing(X);
finally
FreeAndNil(x);
end;
It is important. Because if you have code like this
// don't do something like this
try
X := CreateAnX
DoSomeThing(X);
finally
FreeAndNil(x);
end;
you can be lucky and it works. But if the construction fails you can be "lucky" and get an access violation or you have bad luck and get an access violation some times later at an completely different code position.
An alternative could be
X := nil;
try
X := CreateAnX
DoSomeThing(X);
finally
FreeAndNil(x);
end;
Where to use except depends on what is your intention. When you want to catch every exception and know all calling code clean its problems (using try finally) then an outer except-block is the way to go
try
X := CreateAnX
try
DoSomeThing(X);
finally
FreeAndNil(x);
end;
except
on e: Exception do
LogException(e)
end;
But always think about it when you want catch all errors. As an example (and I often see it wrong) don't do it in an Indy OnExecute-handler this way. There you must use something like this
try
X := CreateAnX
try
DoSomeThing(X);
finally
FreeAndNil(x);
end;
except
on EIdException do
raise;
on e: Exception do
LogException(e)
end;
If you expect an exception because you throw it or (as an example) a conversation can fail, look for the most inner position to catch the error:
X := CreateAnX
try
DoSomeThing(X);
try
i := StrToInt(X.Text);
except
on EConvertError do
i := 0;
end;
finally
FreeAndNil(x);
end;
don't do it this way
X := CreateAnX
try
try
DoSomeThing(X);
i := StrToInt(X.Text);
except
on EConvertError do
i := 0;
end;
finally
FreeAndNil(x);
end;
Do this only if you expect an EConvertError in DoSomeThing too. If DoSomeThing throws an EConvertError and you don't expect it, your code has a serious problem which need to be corrected. In this situation ensure that the user can save his work (perhaps as a copy, because his work could be damaged) and ensure you get the info about the problem.
At least try except is for handling Exceptions not for hiding them.
Related
I was wondering if there are exceptions/errors, which do make your code jump into an except block but aren't handled by E : exception.
try
i := StrToInt(s);
{...do a lot more...}
except
on E : EConvertError do begin
ShowMessage('You need to input a valid number.');
end;
on E : Exception do begin
ShowMessage('Something went wrong.');
Raise;
end;
end;
Is there a way that a program could have an error that would ignore both statements in this except block?
Or should I do it like this :
try
i := StrToInt(s);
{...do a lot more...}
except
on E : EConvertError do begin
ShowMessage('You need to input a valid number.');
end;
else begin // swapped on e : Exception with else
ShowMessage('Something went wrong.');
Raise;
end;
end;
You can throw anything that derives from TObject. In order to catch every such class you'd need to specify TObject in your on statement.
From the documentation:
Exception types are declared just like other classes. In fact, it is possible to use an instance of any class as an exception, but it is recommended that exceptions be derived from the SysUtils.Exception class defined in SysUtils.
In reality I know of no code that throws anything that does not derive from Exception, although #TLama points out one example in a legacy deprecated VCL class in the comments. Certainly StrToInt only throws Exception descendents.
If you don't need to access the exception object you can use a plain except clause without an on statement.
try
....
except
// deal with all exceptions
end;
Or you can use the else clause of an on statement as a catch all, again you won't get immediate access to the exception object.
Otherwise you can specify a base class for the exceptions that you wish to catch. For instance on E: TObject catches everything derived from TObject.
So, as we see, it is possible that things not derived from Exception may be thrown. But you must ask yourself if your code ever does that? If not then it makes most sense to test for Exception in your catch all handlers. That will give you access to the members of Exception. Of course, one does wonder why you have a catch all exception handler. Their existence are often indication of poor design.
Continuing the theme of StrToInt, you only need to catch EConvertError. That's what is raised when the conversion fails. You should ignore any other exception class as, in your example, the code won't know what to do with anything else. One of the goals of writing exception handling code is to handle what you know how to deal with, and ignore everything else.
In fact, TryStrToInt is what you need here:
if TryStrToInt(s, i) then
// do stuff with i
else
// deal with conversion error
This obviates the need to handle any exceptions and makes your code far more readable.
I know that StrToInt is just an example, but it serves quite well to demonstrate the benefits of trying to avoid handling exceptions.
Are there any practical difference between the two coding patterns in Delphi:
Version 1
try
try
{Do something}
finally
{Do tidy up}
end
except
{Handle exception}
end;
Version 2
try
try
{Do something}
except
{Handle exception}
end
finally
{Do tidy up}
end;
There are two differences:
The relative order in which the except and finally blocks execute differs. In version 1, the finally executes before the except. In version 2 the excecution order is reversed.
In version 1, if the finally block raises, then it will be handled by the except block. In version 2, if the finally block raises, then it will be handled by the next containing exception handler, i.e. outside this code.
Usually you aren't concerned about finally blocks that raise. You simply don't expect that to happen and if it does, something is probably very broken.
So the difference that counts is whether the finally runs before the exception handler, or vice versa. Sometimes it doesn't matter, but it often does make a difference.
When you use try..except below lines executed.
Resource := TAbstractResource.Create;
try
Resource.DoSomeThing;
except
On E:Exception Do
HandleException(E);
end;
FreeAndNil(Resource);
There is an example which illustrates my question:
procedure Test;
begin
try
ShowMessage('1');
raise EWarning.Create(12345, 'Warning: something is happens!');
ShowMessage('2');
except
on E: EWarning do
if IWantToContinue(E.ErrorCode) then
E.SkipThisWarning // shows '1' then '2'
else
E.StopExecution; // shows '1'
end;
end;
function IWantToContinue(const ErrorCode: Integer): Boolean;
begin
//...
end;
I tried to use something like this:
asm
jmp ExceptAddr
end;
but it's wont' work...
Any ideas?
Thanks.
No, it is not possible:
There are two kinds of exceptions: logic exceptions that are raised by the programmer using the raise command, and external exceptions that are initiated by the CPU for various conditions: division by zero, stack overflow, access violation. For the first kind, the logic exceptions, there's nothing you can do because they're part of the application "flow". You can't mess with the flow of 3rd party code, you can't even mess with the flow of your own code.
External exceptions
Those are normally raised as a consequence of running a single CPU instruction, when that instruction fails. In Delphi those are made available as EExternal descendants. The list includes access violations, division by zero, stack overflow, privileged instruction and not-so-many others. Theoretically, for some of those exceptions, the causing condition of the exception could be removed and the single CPU instruction retried, allowing the original code to continue as if no error happened. For example SOME access violations might be "fixed" by actually mapping a page of RAM at the address where the error occurred.
There are provisions in the SEH (Structured Exception Handling) mechanism provided by Windows for dealing with such retry-able errors, and Delphi is using SEH under the hood. Unfortunately Delphi doesn't expose the required elements to make this easily accessible, so using them would be very difficult if not impossible. None the less, for particular types of EExternal errors, smart Delphinians might attempt writing custom SEH code and get things working. If that's the case, please ask a new question mentioning the particular type of error you're getting plus the steps you'd like to take to remove the error condition: you'll either get some working code or a customized explanation of why your idea would not work.
Logic exceptions initiated through the use of raise
Most exceptions fall into this category, because most code will check it's inputs before doing potentially dangerous low level stuff. For example, when trying to access an invalid index in a TList, the index would be checked and an invalid index exception raised before attempting to access the requested index. Without the check, accessing the invalid index would either return invalid data or raise an Access Violation. Both of those conditions would be very hard to track errors, so the invalid index exception is a very good thing. For the sake of this question, even if code were allowed to access an invalid index, causing an Access Violation, it would be impossible to "fix" the code and continue, because there's no way to guess what the correct index should be.
In other words, fixing "logic" exceptions doesn't work, shouldn't work, and it's insanely dangerous. If the code that raises the error is yours then you can simply restructure it to NOT raise exceptions for warnings. If that's not your code, then continuing the exception falls into the "insanely dangerous" category (not to mention it's technically not possible). When looking at already written code, ask yourself: would the code behave properly if the raise Exeption were replaced with ShowMessage? The answer should mostly be "NO, the code would fail anyway". For the very rare, very wrong case of 3rd party code that raises an exception for no good reason, you may ask for specific help on patching the code at run-time to NEVER raise the exception.
Here's what could be in some 3rd party code:
function ThirdPartyCode(A, B: Integer): Integer;
begin
if B = 0 then raise Exception.Create('Division by zero is not possible, you called ThirdPartyCode with B=0!');
Result := A div B;
end;
It should be obvious that continuing that code after the exception is not going to allow stuff to "self heal".
Third party code might also look like this:
procedure DoSomeStuff;
begin
if SomeCondition then
begin
// do useful stuff
end
else
raise Exception.Create('Ooops.');
end;
Where would that code "continue"? Quite obviously not the "do usefull stuff" part, unless the code is specifically designed that way.
Those were, of course, simple examples only scratching the surface. From a technical perspective, "continuing" after an exception as you're suggesting is a lot more difficult then jumping to the address of the error. Method calls use stack space to set up local variables. That space was released in the process of "rolling back" after the error, on the way to your exception handler. finally blocks were executed, possibly de-allocating resources where needed. Jumping back to the originating address would be very wrong, because the calling code no longer has what it expects on stack, it's local variables are no longer what they're ment to be.
If it's your code that's raising the exception
Your code can easily be fixed. Use something like this:
procedure Warning(const ErrorText:string);
begin
if not UserWantsToContinue(ErrorText) then
raise Exception.Create(ErrorText);
end;
// in your raising code, replace:
raise Exception.Create('Some Text');
// with:
Warning('Some Text');
AFAIK no. You have to restructure your code to something like
procedure Test;
begin
ShowMessage('1');
try
raise EWarning.Create(12345, 'Warning: something is happens!');
except
on E: EWarning do
if IWantToContinue(E.ErrorCode) then
// shows '1' then '2'
else
raise; // shows '1'
end;
ShowMessage('2');
end;
In C++, it is possible using an SEH __try/__except block whose __except expression evaluates to EXCEPTION_CONTINUE_EXECUTION.
In Delphi, it is not possible to use SEH directly, AFAIK.
BASICally, your code wont work because ExceptAddr is a function, not a variable. So, your code snippet changes as follows:
{$O-}
procedure TForm1.FormCreate(Sender: TObject);
begin
try
OutputDebugString('entering');
raise Exception.Create('Error Message');
OutputDebugString('leaving');
except on E: Exception do
begin
OutputDebugString(PChar(Format('ExceptAddr = %p', [ExceptAddr])));
asm
CALL ExceptAddr
JMP EAX
end;
end;
end;
end;
..you could nest multiple try-except and determine if continue inside each exception:
try
try
some code
except
ret := message('want to continue?');
if ret <> mrYes then
exit;
end;
some other code to perform when no exception or user choose to continue
except
etc..
end;
I have a lot of commands in one procedure and there is this command:
...
Stream:=TFileStream.Create(FileName,fmOpenread);
...
The whole procedure is created to send file from TClientSocket to TServerSocket.
The procedure is launching every 100 milliseconds from Timer. Of course, sometimes I have EFCreateError error showing because the file is used.
Everything works well because some data is received. But how to avoid showing this error?
You need to capture the error and handle it.
See the code below.
....
try
Stream:=TFileStream.Create(FileName,fmOpenread);
except on E: EFCreateError do
Stream:= nil;
end; {try}
if Stream <> nil then try
//rest of your procedure
finally
Stream.Free; //make sure your stream is freed.
end;
If there's an error here, no message will be shown in runtime, in debug you will see an error, but you can ignore that.
On error the Stream variable will be set to nil.
In the code that follows you can test Stream <> nil or Assigned(Stream) (which is the same) and do stuff with the stream if all is well.
I think I see what you mean...
You do handle the exceptions properly, but you want to avoid the Delphi IDE popup for each and every exception that occurs.
If so, do the following:
Go to Tools -> Debugger Options
Go to the Language Exceptions tab
Add EFCreateError to the list of exceptions to ignore
Why don't you wrap the access to the file in a mutex or a read/write lock? Then you wouldn't need to rely on a brittle approach like this.
It also sounds like you are polling a file as an inter process communication mechanism. Something like a pipe is likely to be much more effective.
Using try ... finally to cleanup and try ... except to swallow the expected exception:
Stream := nil; // if it is an unitialized local variable, assign nil
try
try
Stream := TFileStream.Create(Filename, fmOpenread);
except
on E: EFCreateError do
begin
// exception thrown if the file is in use
// and may be ignored in this function
end;
end;
finally
Stream.Free;
end
In some Delphi 7 code I am maintaining, I've noticed a lot of instances of the following:
with ADOQuery1 do begin
// .. fill out sql.text, etc
try
execSQL;
except
raise;
end;
end;
It seems to me that these try blocks could be removed, since they do nothing. However, I am wary of possible subtle side-effects..
Can anyone think of any instances in which these blocks could actually do anything that wouldn't happen without them there?
In this context, the raise operation has no effect and should be removed becuase its simply re-raising the exception that the exception block just caught. raise is typically used to transfer control to the end of the block when no appropriate error handling is available. In the following we handle the custom exception, but any other exception should be handled elsewhere.
try
someOperation;
except
on e: ECustomException do
SomeCustomHandelr;
else
begin
// the raise is only useful to rethrow the exception to an encompasing
// handler. In this case after I have called my logger code. as Rob
// mentioned this can be omitted if you arent handling anything because
// the compiler will simply jump you to the next block if there is no
// else.
LogUnexpectedException('some operation failed',e);
raise;
end;
end;
Be careful that there is similar looking form without the "raise" that DOES have the side effect of eating/hiding any exceptions. practicies by very unscrupulous developers who have hopefully moved on to positions with the competition.
with ADOQuery1 do begin
// .. fill out sql.text, etc
try
execSQL;
except
// no handler so this just eats any "errors"
end;
Removing the except code in above code snippet will make no difference. You can (and I believe you should since it is reducing the readability) remove it.
Okay, really two questions here.
First, it is meaningful: if execSQL throws an exception, it's caught by the try block and forwarded to the except. Then it's forwarded on by the raise to the next higher block.
Second, is it useful? Probably not. It almost certainly is the result of one of three things:
Someone with pointy hair wrote a coding standard that said "all operations that can throw an exception must be in a try block."
Someone meant to come back and turn the exceptions made by the execSQL statment into some other, more meaningful, exception.
Someone new wasn't aware that what they'd written was isomorphic to letting the uter environment worry about the exception, and so thought they must forward it.
I may have answered a bit fast, see at the end...
Like it is, it is useless for the application.
Period!
Now on the "why" side. It may be to standardize the exceptions handling if there /was/will be/is in other places/ some kind of logging code inserted before the raise:
try
execSQL;
except
// Log Exception..
on E: Exception do
begin
LogTrace(Format('%s: Exception Message[%s]',[methodname, E.Message]));
raise;
end;
end;
or for Cleanup code:
try
execSQL;
except
//some FreeAndNil..
raise;
end;
Update: There would be 1 case where I would see some use just like it is...
... to be able to put a Breakpoint on the raise line, to get a chance to see what's going on in the context on that block of code.
This code does nothing, other than to allow the original programmer to place a breakpoint on the 'Raise' and to see the exception closer in the source to its possible cause. In that sense it a perfectly reasonable debugging technique.
Actually, I should posted this as comment to François's answers, but I don't know is it possible to insert formatted code there :( So I'm posting this as answer.
2mghie:
The second one is completely unidiomatic, one would use finally instead.
No, "finally" will cleanup object always. "Except" - only on exception. Consider the case of function, which creates, fills and return an object:
function CreateObj: TSomeObj;
begin
Result := TSomeObj.Create;
try
... // do something with Result: load data, fill props, etc.
except
FreeAndNil(Result); // oops: bad things happened. Free object to avoid leak.
raise;
end;
end;
If you put "finally" there - function will return nil always. If you omit "try" block at all - there will be resources leak in case of exception in "...".
P.S. Of course, you can use "finally" and check ExceptObj, but... isn't that ugly?
The title contains quite a broad question, while its explanation gives a more specific example. So, my answering to the question as how it proceeds from the example, can doubtly add anything useful to what has already been said here.
But, maybe Blorgbeard indeed wants to know whether it is at all meaningful to try ... except raise; end. In Delphi 7, if I recollect correctly, Exit would trigger the finally part of a try-finally block (as if it were some sort of exception). Someone might consider such behaviour inappropriate for their task, and using the construction in question is quite a workaround.
Only it would still be strange to use a single raise; there, but then we should have talked about usefulness rather than meaningfulness, as Charlie has neatly observed.
This code does nothing except re-raising an exception that will allready be raised without this try except block. You can safely remove it.