David Hoyle 68 Posted September 2, 2019 I wonder if anyone can either confirm I'm not going insane and this is a bug I need to report or tell me what I'm doing wrong. Eurekalog has found a bug in my application and I've managed to decant it down to the following code - it takes a pair of integers and sorts them by the FPosition field (code to get the display order of a VirtualStringTree). The commented out line in Test() should not be required in my mind as the IComparer interface should be released when it goes out of scope at the end of the Test() function but it doesn't for me (I'm using 10.3.2). Program ComparerFreeing; {$APPTYPE CONSOLE} {$R *.res} Uses System.SysUtils, System.Generics.Collections, System.Generics.Defaults; Type TXTColumnPosition = Record FIndex, FPosition : Integer; End; TXTColumnPositionComparer = Class(TInterfacedObject, IComparer<TXTColumnPosition>) Public Constructor Create; Destructor Destroy; Override; Function Compare(Const Left, Right : TXTColumnPosition) : Integer; End; Function TXTColumnPositionComparer.Compare(Const Left, Right: TXTColumnPosition): Integer; Begin Result := Left.FPosition - Right.FPosition; End; Constructor TXTColumnPositionComparer.Create; Begin WriteLn('Create'); Inherited; End; Destructor TXTColumnPositionComparer.Destroy; Begin WriteLn('Destroy'); Inherited; End; Function Test : TArray<TXTColumnPosition>; Var Comparer: TXTColumnPositionComparer; Begin SetLength(Result, 5); // Result[0].FIndex := 0; // Result[0].FPosition := 4; // Result[1].FIndex := 1; // Result[1].FPosition := 3; // Result[2].FIndex := 2; // Dummy setup for testing Result[2].FPosition := 2; // Result[3].FIndex := 3; // Result[3].FPosition := 1; // Result[4].FIndex := 5; // Result[4].FPosition := 0; // Comparer := TXTColumnPositionComparer.Create; System.Generics.Collections.TArray.Sort<TXTColumnPosition>(Result, Comparer); //: @debug Comparer.DisposeOf; // Required to release the interface End; Var aInts : TArray<TXTColumnPosition>; i : Integer; Begin Try aInts := Test; For i := Low(aInts) To High(aInts) Do WriteLn(aInts[i].FIndex, ' => ', aInts[i].FPosition); ReadLn; Except On E: Exception Do Writeln(E.ClassName, ': ', E.Message); End; End. I get the following output from the above... Create 5 => 0 3 => 1 2 => 2 1 => 3 0 => 4 i.e. Destroy is not called. Share this post Link to post
David Hoyle 68 Posted September 2, 2019 Ignore me, should have checked QP first: https://quality.embarcadero.com/browse/RSP-15797. Share this post Link to post
Stefan Glienke 2002 Posted September 3, 2019 Mixing of object and interface references with a const interface param. Solution: declare the Comparer var as IComparer<TXTColumnPosition> 1 Share this post Link to post
David Hoyle 68 Posted September 3, 2019 Thank's Stefan. Originally I had the following... System.Generics.Collections.TArray.Sort<TXTColumnPosition>(Result, TXTColumnPositionComparer.Create); and that would release. I changed it while trying to find out why. I'll change it as you suggest (I should have noticed that) and see if it works. Share this post Link to post
Stefan Glienke 2002 Posted September 3, 2019 (edited) No, that would not release either - thats one of those bugs people keep reporting since ages and Embarcadero refuse to fix - I think @Dalija Prasnikar remembers the according QP entry. FWIW unless the comparer needs its own state you don't even need to create your own class, just pass a function(const left, right: T): Integer to TComparer<T>.Construct fwiw in Spring I added overloads to all methods taking IComparer<T> to also directly accept that - makes using them way more comfortable. Edited September 3, 2019 by Stefan Glienke Share this post Link to post
David Heffernan 2345 Posted September 3, 2019 The const param reference counting bug that keeps on giving. https://stackoverflow.com/a/31028671/505088 https://stackoverflow.com/a/7640979/505088 https://stackoverflow.com/q/4509015/505088 QC report 90482 and presumably many others. Of course, Emba killed QC. Thanks so much for that. Can I be arsed to re-enter all the unsolved reports that were killed when QC was killed? No I cannot. 1 Share this post Link to post
Dalija Prasnikar 1396 Posted September 3, 2019 Memory-Leak on Const-Parameter https://quality.embarcadero.com/browse/RSP-10100 Also specifically for ARC compiler, above problem can also cause crashes (linked with above report) Leaks or crashes on passing freshly created object instances directly as interface parameters https://quality.embarcadero.com/browse/RSP-17071 Share this post Link to post
David Hoyle 68 Posted September 3, 2019 Thank you @David Heffernan and @Dalija Prasnikar. Share this post Link to post
Der schöne Günther 316 Posted September 3, 2019 It's beyond me why, if it's never getting fixed, why they can't at least add a compiler warning. We don't even have warnings for the most obvious mistakes like using an uninitialized return value or this. I don't understand why. Share this post Link to post
Dalija Prasnikar 1396 Posted September 3, 2019 1 hour ago, Der schöne Günther said: It's beyond me why, if it's never getting fixed, why they can't at least add a compiler warning. We don't even have warnings for the most obvious mistakes like using an uninitialized return value or this. I don't understand why. If they add warning they could just as well fix it... Seriously, no matter how hard I try, I cannot figure out the real reason why... Share this post Link to post