Recent

Author Topic: Freeing an Object with multiple References on it  (Read 2493 times)

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Freeing an Object with multiple References on it
« on: April 14, 2022, 08:47:49 am »
Hello,

i have a Problem when i try to free an Object.

i have a class:
Code: Pascal  [Select][+][-]
  1. TCube = class
  2.    private
  3.       { ----- Variables ----- }
  4.       //....
  5.       fViewModel: TBtlViewModel;
  6.  
  7.       { ----- Getter / Setter -----}
  8.       //....
  9.    public
  10.  
  11.       { ----- Properties ----- }
  12.       //....
  13.       property ViewModel: TBtlViewModel read fViewModel;
  14.  
  15.       { ----- Methods ----- }
  16.       constructor Create(cArt: TBtlType; cZLAL: TAirFlowType; cViewModel: TBtlViewModel); overload;
  17.       constructor Create(cArt: TBtlType; cZLAL: TAirFlowType); overload;
  18.      //...
  19.  
  20.  

created like this:
Code: Pascal  [Select][+][-]
  1. constructor TCube.Create(cArt: TBtlType; cZLAL: TAirFlowType; cViewModel: TBtlViewModel); overload;
  2. begin
  3.    //...
  4.    fViewModel:= cViewModel;
  5.    //...
  6. end;
  7.  
  8. constructor TCube.Create(cArt: TBtlType; cZLAL: TAirFlowType);
  9. begin
  10.    //...
  11.    fViewModel:= TSubViewModel.Create; //TSubViewModel is a Sub class of TBtlViewModel
  12.    //...
  13. end;
  14.  


i have two cubes then wich should point to the same Viewmodel:

Code: Pascal  [Select][+][-]
  1.    baseCube:= TCube.Create(3, 0);
  2.    SecCube:= TCube.Create(baseCube.Art, 1, baseCube.ViewModel);
  3.  

they get removed together like this:

Code: Pascal  [Select][+][-]
  1. destructor TCube.Destroy;
  2. begin
  3.    //...
  4.    if Assigned(fViewModel) then
  5.       fViewModel.Free;
  6.  
  7.    inherited Destroy;
  8. end;
  9.  

i create Two cubes and then Destroy them, do it again, and on the third time i  get Access violation. i tried using FreeAndNil, but that didn't help.
how do i check if the Viewmodel is already Freed ? or how do i Nil the References to this Object on other Objects.
« Last Edit: April 14, 2022, 08:51:53 am by Weitentaaal »

MarkMLl

  • Hero Member
  • *****
  • Posts: 8562
Re: Freeing an Object with multiple References on it
« Reply #1 on: April 14, 2022, 09:11:09 am »
I had something similar a couple of weeks ago. I think that nilling references and possibly also counting them (even if only for the purpose of assertions) is a good move, possibly by implementing various Delete() methods that delete child objects etc.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

bytebites

  • Hero Member
  • *****
  • Posts: 778
Re: Freeing an Object with multiple References on it
« Reply #2 on: April 14, 2022, 09:14:18 am »
Code: Pascal  [Select][+][-]
  1. destructor TCube.Destroy;
  2. begin
  3.    //...
  4.    if createdhere and Assigned(fViewModel) then
  5.       fViewModel.Free;
  6.  
  7.    inherited Destroy;
  8. end;
  9.  

Code: Pascal  [Select][+][-]
  1. constructor TCube.Create(cArt: TBtlType; cZLAL: TAirFlowType);
  2. begin
  3.    //...
  4.    fViewModel:= TSubViewModel.Create; //TSubViewModel is a Sub class of TBtlViewModel
  5.    createdhere:=true
  6.    //...
  7. end;

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Freeing an Object with multiple References on it
« Reply #3 on: April 14, 2022, 09:24:17 am »
Thanks,

Quote
FreeAndNil is a procedure defined in the SysUtils unit of the Free Pascal Runtime Library. It calls an object's destructor (via TObject.Free) and also sets the object variable (which is a reference to heap memory created by a constructor call) to nil. If you just call an object's destructor, Assigned will still return True for the object variable. But after calling FreeAndNil, Assigned will return False for the object variable. While the procedure has an untyped parameter, it is only for use with object references - that is variables that are instances of a Class.

Just to get it right. After the Documentation of FreeAndNil, Assigned should return False. did i misunderstand something here ?
« Last Edit: April 14, 2022, 10:08:11 am by Weitentaaal »

MarkMLl

  • Hero Member
  • *****
  • Posts: 8562
Re: Freeing an Object with multiple References on it
« Reply #4 on: April 14, 2022, 09:48:10 am »
First, where is that quote from? Second, throwing in FreeAndNil() won't automatically protect you from things being freed in an unexpected order.

The thing that caused me problems is when I was putting something into a list using TList.Add(), and then FreeAndNilling the instance. Redefining TList.Add() to nil its parameter fixed that.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Freeing an Object with multiple References on it
« Reply #5 on: April 14, 2022, 10:03:30 am »
Source: https://wiki.lazarus.freepascal.org/FreeAndNil

And Yes it should not protect me from things being freed in an unexpected order. But i could check with "Assigned" if the Object is not Freed yet. If so i could FreeAndNil it. Any other Objects in my Example wouldn't try to Free it then, because Assigned would result in False.

in the Example of "https://wiki.lazarus.freepascal.org/FreeAndNil" it said:
"// assigning Nil after destructor is called is the same as
 // FreeAndNil"

So after i would try Assigned(SomeObject) after using FreeAndNil(SomeObject), i would get Nil if i didn't misunderstood
« Last Edit: April 14, 2022, 10:08:01 am by Weitentaaal »

MarkMLl

  • Hero Member
  • *****
  • Posts: 8562
Re: Freeing an Object with multiple References on it
« Reply #6 on: April 14, 2022, 10:12:51 am »
Source: https://wiki.lazarus.freepascal.org/FreeAndNil

Wiki is not documentation, it's exegesis and potentially unreliable. Documentation is at https://www.freepascal.org/docs-html/current/rtl/sysutils/freeandnil.html (note: current version of FPC, which is not necessarily what you're using).

Quote
And Yes it should not protect me from things being freed in an unexpected order. But i could check with "Assigned" if the Object is not Freed yet. If so i could FreeAndNil it. Any other Objects in my Example wouldn't try to Free it then, because Assigned would result in False.

Yes, in principle. In practice it's not foolproof, as in the example I gave.

There was debate about this a few weeks ago, with some people appearing to maintain that FreeAndNil() was undesirable since it hid issues of poor program design. I'm not one of those, since (reductio ad absurdum) a properly-designed program should be written in assembler with none of this high-level language crap making it easier.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Freeing an Object with multiple References on it
« Reply #7 on: April 14, 2022, 10:52:10 am »
Thank you, your answer has covered all my questions ! :D

MarkMLl

  • Hero Member
  • *****
  • Posts: 8562
Re: Freeing an Object with multiple References on it
« Reply #8 on: April 14, 2022, 11:46:57 am »
:-) I suggest bookmarking

https://www.freepascal.org/docs.html

and

https://lazarus-ccr.sourceforge.io/docs/

The first of those covers current FPC etc. (although the .pdf links still haven't been fixed), the second covers current Lazarus/LCL and the version of FPC it uses (which is not necessarily the same).

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Bart

  • Hero Member
  • *****
  • Posts: 5712
    • Bart en Mariska's Webstek
Re: Freeing an Object with multiple References on it
« Reply #9 on: April 14, 2022, 12:20:58 pm »
Isn't this a problem for which FreeNotification was invented?
(I may be entrirely wrong though.)

Bart

MarkMLl

  • Hero Member
  • *****
  • Posts: 8562
Re: Freeing an Object with multiple References on it
« Reply #10 on: April 14, 2022, 12:37:59 pm »
What implements that? Cursory inspection doesn't show it under the RTL, FCL or LCL indexes.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

kupferstecher

  • Hero Member
  • *****
  • Posts: 617
Re: Freeing an Object with multiple References on it
« Reply #11 on: April 14, 2022, 12:55:36 pm »
But i could check with "Assigned" if the Object is not Freed yet.
Not sure if this is clear, yet. But "Assigned" only checks if the variable is nil or not. You access FreeAndNil from one variable and in this statement only this variable is set to nil. The other one still contains the memory address of the instance, although the instance doesn't exist any more. If you now use "Assigned" for this other variable, it will return true, because it contains an address other than nil. "Assigned" doesn't check what actually is at that address. So as bytebites suggested you can use a boolean flag, that stores if the tViewModel is an externally created instance. You could also implement something like a owner.

Code: Pascal  [Select][+][-]
  1. constructor TCube.Create(cArt: TBtlType; cZLAL: TAirFlowType);
  2. begin
  3.   fViewModel:= TSubViewModel.Create;
  4.   fViewModel.Owner:= self;
  5. end;
  6.  
  7. destructor TCube.Destroy;
  8. begin
  9.   if fViewModel.Owner = self
  10.   then fViewModel.Free;
  11.  end;

Weitentaaal

  • Hero Member
  • *****
  • Posts: 554
Re: Freeing an Object with multiple References on it
« Reply #12 on: April 14, 2022, 01:16:03 pm »
i'm using a Owner now. works fine.

Bart

  • Hero Member
  • *****
  • Posts: 5712
    • Bart en Mariska's Webstek
Re: Freeing an Object with multiple References on it
« Reply #13 on: April 14, 2022, 06:56:21 pm »
What implements that? Cursory inspection doesn't show it under the RTL, FCL or LCL indexes.
TComponent AFAIK.

Bart

MarkMLl

  • Hero Member
  • *****
  • Posts: 8562
Re: Freeing an Object with multiple References on it
« Reply #14 on: April 14, 2022, 07:38:07 pm »
What implements that? Cursory inspection doesn't show it under the RTL, FCL or LCL indexes.
TComponent AFAIK.

Bart

OK, but this is a general Pascal topic so doesn't assume availability of the LCL etc.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018