Do I need to free the enumerator returned by GetEnumerator?
Asked Answered
C

1

7

I want to use the enumerator for a generic collection with Delphi XE2. I am wondering, who owns the TEnumerator returned by the function GetEnumerator (I haven't found any clear answer in the documentation):

  • Do I own it and need to free it after use?
  • Or is it owned by the collection and I don't have to care about releasing it?

Code:

procedure Test;
var
  myDictionary: TDictionary<String, String>;
  myEnum: TDictionary<String, String>.TPairEnumerator;
begin
  { Create a dictionary }
  myDictionary := TDictionary<String, String>.Create;
  myDictionary.Add('Key1', 'Value 1');
  myDictionary.Add('Key2', 'Value 2');

  { Use an enumerator }
  myEnum := myDictionary.GetEnumerator;
  // ... do something with the Enumerator ...

  { Release objects }
  myEnum.Free; // ** Do I need to free the enumerator? **
  myDictionary.Free;          
end;
Condole answered 15/3, 2012 at 11:15 Comment(3)
you can also test this by adding "ReportMemoryLeaksOnShutdown := True" as the first line after begin in your project's source, in this way you can test various other leaks.Subdominant
@DorinDuminica ReportMemoryLeaksOnShutdown := True also works if it is not the first lineGudren
@Gudren thank you, I forgot to edit it, after wrote the above comment, I've read somewhere(can't remember) that it's OK to change the flag in any part of the code, but still it's a good idea to have it somewhere "easily accessible" without having to search in files...Subdominant
F
6

If you look at the source of TDictionary, you will find that GetEnumerator (in its ancestor) calls DoGetEnumerator which in TDictionary calls a reintroduced version of GetEnumerator.

The reintroduced TDictionary.GetEnumerator creates a TPairEnumerator instance passing itself as the dictionary to be enumerated. The dictionary does not hold a reference to the TPairEnumerator. The PairEnumerator does not get notified of the destruction of its dictionary.

So, yes you do need to free the enumerator yourself and to avoid any access violations you really should do that before destroying the dictionary that it enumerates.

Frisket answered 15/3, 2012 at 11:40 Comment(4)
in case of using for-in loop, we don't have reference to enumerator (it is hidden); does Delphi free it itself?Droll
@teran: yes, the compiler adds the necessary magic to free the hidden enumerator.Erickericka
@UweRaabe, yes, i've just checked :) really I think for-in loop stores enumerator as reference to IEnumerable (I suppose it creates new object, wich supports IEnumerable<> and owns our Enumerator object, so it destroys our enumerator in the end of loop. because of that, Embarcadero recommends to implement IEnumerable to make containers enumerable - docwiki.embarcadero.com/Libraries/en/System.IEnumerable)Droll
I changed the release order in my example so that it is now in the same order as you suggested!Condole

© 2022 - 2024 — McMap. All rights reserved.