Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2013-03

exception handling in constructor

8 messages · 6 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Xiangrong Fang

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.
2. the MyInstance variable is assigned *nil*?

Thanks
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20130302/d25feaa8/attachment.html>

Reply by email

Flávio Etrusco
to Xiangrong Fang
Xiangrong Fang wrote 19 lines
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.

Thanks

Regards,
Fl?vio

Reply by email

Sven Barth
to Xiangrong Fang: If my class constructor looks like this: constructor TMyClass.Create(fn: string); begin…
Xiangrong Fang wrote 13 lines
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;

No, this is a bad idea. If an exception occurs inside the constructor the destructor will be called automatically. I don't even want to think about what bad things could happen if you call Destroy inside the constructor...

Show quoted text 5 lines
I create the objec like: MyInstance := TMyClass.Create('AnNonExistentFile'); An exception occured, I can ensure that: 1. there is no memory leak.

There won't be a memory leak.

2. the MyInstance variable is assigned *nil*?

If you want to ensure that MyInstance is Nil you need to do it like this:

=== code begin ===

try
   MyInstance := TMyClass.Create('AnNonExistentFile');
except
   MyInstance := Nil;
end;

=== code end ===

Regards,
Sven

Reply by email

Howard Page-Clark
to Flávio Etrusco: I assume FPC behaves like Delphi, so there's no leak. Actually, you don't even need to…
Fl?vio Etrusco wrote 29 lines
On Fri, Mar 1, 2013 at 11:49 PM, Xiangrong Fang 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.

Reply by email

Michael Van Canneyt
to Howard Page-Clark
Howard Page-Clark wrote 46 lines
On 02/03/13 5:45, Fl?vio Etrusco wrote: > On Fri, Mar 1, 2013 at 11:49 PM, Xiangrong Fang 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.

Reply by email

Hans-Peter Diettrich
to Sven Barth: No, this is a bad idea. If an exception occurs inside the constructor the destructor will…
Show quoted text 11 lines
If you want to ensure that MyInstance is Nil you need to do it like this: === code begin === try MyInstance := TMyClass.Create('AnNonExistentFile'); except MyInstance := Nil; end; === code end ===

When an exception occurs in Create, the assignment will never take place. That's why MyInstance should be set to Nil *before* calling the constructor. This also applies to memory leak protection of multiple temporary objects:

inst1 := nil;
inst2 := nil;
...
try
   inst1 := T1.Create;
   inst2 := T2.Create;
   ...
finally
   inst1.Free;
   inst2.Free;
   ...
end;

The Free does no harm, even if the instances never were created, when the variables are nil'ed before the try block.

DoDi

Reply by email

Flávio Etrusco
to Michael Van Canneyt: This will definitely cause a memory leak, because the FPC code does not know that an…
Michael Van Canneyt wrote 8 lines
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 wrote: >>>

(...)

Show quoted text 6 lines
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.

Wow, this is unexpected. I always thougth that by definition a constructor would never return nil - so Self was a "by-value" parameter, even inside a constructor.
Is this by design?
I never saw the point of allowing assign to Self,...

-Fl?vio

Reply by email