[Lazarus] exception handling in constructor

Michael Van Canneyt michael at freepascal.org
Sat Mar 2 11:51:17 CET 2013



On Sat, 2 Mar 2013, Howard Page-Clark wrote:

> On 02/03/13 5:45, Flávio Etrusco wrote:
>> On Fri, Mar 1, 2013 at 11:49 PM, Xiangrong Fang <xrfang at gmail.com> wrote:
>>> Hi there,
>>> 
>>> If my class constructor looks like this:
>>> 
>>> constructor TMyClass.Create(fn: string);
>>> begin
>>>    sl := TStringList.Create;
>>>    try
>>>      fs := TFileStream.Create(fn, fmOpenRead);
>>>    except
>>>      self.Destroy;
>>>    end;
>>> end;
>>> 
>>> I create the objec like:  MyInstance :=
>>> TMyClass.Create('AnNonExistentFile');  An exception occured, I can ensure
>>> that:
>>> 
>>> 1. there is no memory leak.
>> 
>> I assume FPC behaves like Delphi, so there's no leak.
>> Actually, you don't even need to explicitly call Destroy; when an
>> exception occurs in a constructor the destructor is called
>> automatically.
>> 
>>> 2. the MyInstance variable is assigned nil?
>> 
>> No, it's not initialized.
>
> But you can write:
>
> constructor TMyClass.Create(fn: string);
> var fs: TFileStream;
> begin
>  sl := TStringList.Create;
>  try
>    fs := TFileStream.Create(fn, fmOpenRead);
>  except
>    self:= nil;
>  end;
> end;
>
> which gives no memory leak, (provided your destructor frees the stringlist 
> sl) and also ensures MyInstance is assigned a nil value.

This will definitely cause a memory leak, because the FPC code does 
not know that an exception occurred in the constructor (you catch it with Except), 
and hence will not call the destructor.

Heap dump by heaptrc unit
27 memory blocks allocated : 2067/2104
25 memory blocks freed     : 1947/1984
2 unfreed memory blocks : 120
True heap size : 425984
True free heap : 425568
Should be : 425608
Call trace for block $00007FEF86F892C0 size 104
   $000000000041205C
   $0000000000411D4A
   $0000000000400283 line 15 of tm.pp
   $00000000004004CC line 30 of tm.pp
   $000000000040018F
Call trace for block $00007FEF86F810C0 size 16
   $000000000041205C
   $00000000004001F7 line 14 of tm.pp
   $00000000004004CC line 30 of tm.pp
   $000000000040018F

Also, setting Self to nil is nonsense.

If you do FreeAndNil(Self) instead, it will work.

But I would seriously warn against doing this kind of thing.

The idea of exceptions is exactly to let the exception propagate to callers, 
so they know something is wrong. With the code as you propose, 
MyInstance is nil, without any notification whatsoever that something went wrong or what exactly went wrong.

Michael.


More information about the Lazarus mailing list