Recent

Author Topic: [solved]Initialising a not yet created class  (Read 2420 times)

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
[solved]Initialising a not yet created class
« on: December 06, 2018, 04:24:26 am »
I have some code where I use a TStringList after a spot that may raise an exception. I handle that exception and free the string list in the finally clause. At that stage, the List may, or may not have been created, freeandnil(list) cannot tell unless I set List to nil myself. Is that how it should work ?

A much simplified version -

Code: Pascal  [Select][+][-]
  1. var
  2.     List : TStringList;
  3. begin
  4.     List := Nil;       //  This is what I am asking about !
  5.     try
  6.        SomeCrashProneThing()
  7.        List := TStringList.Create;
  8.        DoSomething();
  9.     finally
  10.         FreeandNil(List);
  11.     end;
  12. end;
  13.  

I find that without the List := nil; line, FreeAndNil() does a seg V  because its trying to free something thats not been allocated. Its not hard to add that line but I am a bit surprised I need to. Or, I guess, I could create the list earlier in the function.

Ah, I should have shown that snip of code as being in a method, "the compiler initializes global class variables...."

Davo
« Last Edit: December 06, 2018, 06:19:27 am by dbannon »
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: Initialising a not yet created class
« Reply #1 on: December 06, 2018, 04:31:33 am »
Maybe:
Code: Pascal  [Select][+][-]
  1. var
  2.   List: TStringList;
  3.   hasCreated: Boolean;
  4.  
  5. begin
  6.   List := nil;
  7.   hasCreated := False;
  8.   try
  9.     SomeCrashProneThing();
  10.     List := TStringList.Create;
  11.     hasCreated := True;
  12.     DoSomething();
  13.   finally
  14.     if hasCreated then FreeAndNil(List);
  15.   end;
  16. end;

or

Code: Pascal  [Select][+][-]
  1.   if List <> nil then FreeAndNil(List);
« Last Edit: December 06, 2018, 04:39:03 am by Handoko »

HeavyUser

  • Sr. Member
  • ****
  • Posts: 397
Re: Initialising a not yet created class
« Reply #2 on: December 06, 2018, 05:00:29 am »
I have some code where I use a TStringList after a spot that may raise an exception. I handle that exception and free the string list in the finally clause. At that stage, the List may, or may not have been created, freeandnil(list) cannot tell unless I set List to nil myself. Is that how it should work ?

A much simplified version -

Code: Pascal  [Select][+][-]
  1. var
  2.     List : TStringList;
  3. begin
  4.     List := Nil;       //  This is what I am asking about !
  5.     try
  6.        SomeCrashProneThing()
  7.        List := TStringList.Create;
  8.        DoSomething();
  9.     finally
  10.         FreeandNil(List);
  11.     end;
  12. end;
  13.  

I find that without the List := nil; line, FreeAndNil() does a seg V  because its trying to free something thats not been allocated. Its not hard to add that line but I am a bit surprised I need to. Or, I guess, I could create the list earlier in the function.

Ah, I should have shown that snip of code as being in a method, "the compiler initializes global class variables...."

Davo
Yes that is one way to handle it. If my memory serves me right freeandNil is safe to use on nil pointers as well. The way I've used most though is nested try..finally blocks. eg.
Code: Pascal  [Select][+][-]
  1. var
  2.     List : TStringList = Nil;//FYI in declaration initialization is supported.
  3. begin
  4.   //initialization code in here. mostly safe to execute ee constructors and such.
  5.   try
  6.     SomeCrashProneThing()
  7.     //if the constructor raises an exception for all intents and purposes
  8.     //assume that the memory was never allocated.
  9.     List := TStringList.Create;
  10.     try
  11.       //if anything goes wrong in here the clean up will run.
  12.       DoSomething();
  13.     finally
  14.       FreeandNil(List);
  15.     end;
  16.   finally
  17.     //clean up previous initialization as needed.
  18.   end;
  19. end;

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: Initialising a not yet created class
« Reply #3 on: December 06, 2018, 05:15:42 am »
I have some code where I use a TStringList after a spot that may raise an exception. I handle that exception and free the string list in the finally clause. At that stage, the List may, or may not have been created,
Don't do that. Need:
Code: Pascal  [Select][+][-]
  1. AllocateResource;
  2. try
  3.   WorkWithResource;
  4. finally
  5.   FreeResource;
  6. end;
Are you confused with try except. These are different statements they only have the word try in common.

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Initialising a not yet created class
« Reply #4 on: December 06, 2018, 06:19:04 am »
Thanks Folks !

Useful info from all. Yep, HeavyUser, my experiments indicate that FreeandNil() is safe to call as long as you are setting the declared variable to nil or creating the class before any risky behavior.

So, whenever I declare a class object in a Method (globals are different) I will now do -

Code: Pascal  [Select][+][-]
  1. var
  2.     List : TStringList = nil;

I think the extra processing effort is negligible and its only 6 extra characters for me to type.

Handoko's idea of declaring and maintaining a bool is very through but I suspect its overkill. And it does add that touch of extra processing and memory and, maybe might not be fool (ie fool programmers like me) proof. ASerge likes to create the class as soon as possible, before you get into the space where things go wrong. Pretty fool proof but sometimes (in my case) unnecessary processing and memory ?

All depends on how careful you are and want to be I guess !

Thanks folks !



Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

mangakissa

  • Hero Member
  • *****
  • Posts: 1131
Re: [solved]Initialising a not yet created class
« Reply #5 on: December 06, 2018, 08:53:55 am »
Why using FreeandNil for TStringlist?
Lazarus 2.06 (64b) / FPC 3.0.4 / Windows 10
stucked on Delphi 10.3.1

BrunoK

  • Sr. Member
  • ****
  • Posts: 452
  • Retired programmer
Re: [solved]Initialising a not yet created class
« Reply #6 on: December 06, 2018, 11:12:23 am »
Code: Pascal  [Select][+][-]
  1. var
  2.     List : TStringList = nil;
  3. begin
  4.     try
  5.        SomeCrashProneThing()
  6.        List := TStringList.Create;
  7.        DoSomething();
  8.     finally
  9.        FreeAndNil(List); // <<<< List.Free will also work because TObject free checks for Self <> nil
  10.     end;
  11. end;
Why using FreeandNil for TStringlist?
Because its sometimes useful further in a code block/procedure to know if a variable is instantiated or not, such in :
Code: Pascal  [Select][+][-]
  1. if Assigned(List) then { If the list exist do something with it }
  2.   ProcessList(List);

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: [solved]Initialising a not yet created class
« Reply #7 on: December 06, 2018, 11:37:02 am »
Code: Pascal  [Select][+][-]
  1. var
  2.     List : TStringList = nil;
  3. begin
  4.     try
  5.        SomeCrashProneThing()
  6.        List := TStringList.Create;
  7.        DoSomething();
  8.     finally
  9.        FreeAndNil(List); // <<<< List.Free will also work because TObject free checks for Self <> nil
  10.     end;
  11. end;
Why complicate the code? And if you then delete the initialization or re-use the variable?
Code: Pascal  [Select][+][-]
  1. var
  2.   List: TStringList;
  3. begin
  4.   SomeCrashProneThing;
  5.   List := TStringList.Create;
  6.   try
  7.     DoSomething;
  8.   finally
  9.     List.Free;
  10.   end;
  11. end;

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
Re: [solved]Initialising a not yet created class
« Reply #8 on: December 06, 2018, 12:14:03 pm »
SomeCrashProneThing should be inside the try ... finally block.

HeavyUser

  • Sr. Member
  • ****
  • Posts: 397
Re: [solved]Initialising a not yet created class
« Reply #9 on: December 06, 2018, 12:37:01 pm »
SomeCrashProneThing should be inside the try ... finally block.
makes no difference if it is in or out, if the finally block has nothing to do. aSerge's last post is the minimal piece of code to solve the problem presented (no allocation of resources used by the somecrashpronecode) and minimal is less code = less opportunity to introduce a bug. among all posters in this thread all bases are covered and the OP reminded some old tricks or even learned a few new ones.

 

TinyPortal © 2005-2018