TStrings is returned as "Invalid value" when an exception occurs in a function

Can someone help me explain why TStrings returns as "Invalid value" when an exception occurs in the underlyning function?

function GetStrings():TStrings; begin result := TStringList.Create; try raise exception.Create('Error Message'); except FreeAndNil(result); raise end; end; procedure TFormMain.Button1Click(Sender: TObject); var S : TStrings; begin 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; end; 

The GetStrings function also returns an "Invalid value" if I do not call FreeAndNil(result); until the exception is thrown again. However, I also have a memory leak on my hands: -O

+5
source share
1 answer
 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.

+6
source

Source: https://habr.com/ru/post/1200334/


All Articles