try S := GetStrings; try //Do awesome stuff finally FreeAndNil(S) end; except //Debug watch: S = "Inaccessible value" Assert(S = nil, 'Assertion failure, S should be nil'); end;
Here is the execution sequence:
- Since
S is a local variable, its value is indefinite until it is initialized. This is the state when this code starts execution. - The
GetStrings function is GetStrings . - An exception is
GetStrings in GetStrings . This means that GetStrings does not return execution to the caller, and therefore has a value that S never assigned. - The
finally block is not executed because its attempt has never been reached. - Next, the
except block is executed, and S has an undefined value that you observed.
In fact, the compiler should warn (W1036) that S may not be initialized when you reference it in an except block. But it does not seem to be able to do this, which is rather pathetic.
If you want to be able to reference S in your except block, you will need to nest it in try/finally .
S := GetStrings; try try //Do awesome stuff except //Do stuff with S Assert(S <> nil); end; finally FreeAndNil(S) end;
Another way to think about this is that S only makes sense between the code that assigns S and the code that destroys the object. The consequence is that try/except must be nested inside try/finally if the except block is able to refer to the object.
source share