Records que possuem tipos gerenciados não devem ser usados como retorno de funções sem que se tome alguns cuidados, isso não deve ser feito a não ser que seja estritamente necessário, como quando precisamos de um método get em um objeto para acessar uma propriedade indexada do tipo do record. Tirando isso, a forma correta é sempre retornar tais records em parâmetros out

形式
Delphi
投稿日時
2021-10-23 01:48
公開期間
無期限
  1. program MemLeaks;
  2. {$APPTYPE CONSOLE}
  3. {$R *.res}
  4. uses
  5. System.SysUtils, WinApi.Windows;
  6. type
  7. // Declaração do record com um tipo gerenciado (string)
  8. TMyRecord = record
  9. Id: Byte;
  10. Description: String;
  11. end;
  12. // Declaração do array dinâmico onde cada um de seus itens é um TMyRecord
  13. TMyRecords = array of TMyRecord;
  14. // Função que preenche a variável passada em seu parâmetro (um array) com 16
  15. // elementos do tipo TMyRecord
  16. procedure FillMyRecords(out AMyRecords: TMyRecords);
  17. var
  18. i: Word;
  19. begin
  20. SetLength(AMyRecords,16);
  21. for i := 0 to Pred(16) do
  22. begin
  23. AMyRecords[i].Id := i;
  24. AMyRecords[i].Description := 'Item ' + IntToStr(i);
  25. end;
  26. end;
  27. var
  28. MyRecords: TMyRecords;
  29. // Funções que obtém um TMyRecord a partir de seu Id informado no parâmetro AId.
  30. function GetRecord1(AId: Byte): TMyRecord;
  31. var
  32. i: Byte;
  33. begin
  34. // Zera a memória de Result gerando memory leaks
  35. ZeroMemory(@Result,SizeOf(TMyRecord));
  36. for i := 0 to High(MyRecords) do
  37. if MyRecords[i].Id = AId then
  38. begin
  39. Result := MyRecords[i];
  40. Break;
  41. end;
  42. end;
  43. function GetRecord2(AId: Byte): TMyRecord;
  44. var
  45. i: Byte;
  46. begin
  47. // Zera a memória de Result sem gerar memory leaks (Delphi XE7+)
  48. Result := Default(TMyRecord);
  49. for i := 0 to High(MyRecords) do
  50. if MyRecords[i].Id = AId then
  51. begin
  52. Result := MyRecords[i];
  53. Break;
  54. end;
  55. end;
  56. function GetRecord3(AId: Byte): TMyRecord;
  57. var
  58. i: Byte;
  59. begin
  60. // Zera a memória de Result sem gerar memory leaks (Delphi 2006 e talvez mais
  61. // antigos)
  62. Finalize(Result);
  63. for i := 0 to High(MyRecords) do
  64. if MyRecords[i].Id = AId then
  65. begin
  66. Result := MyRecords[i];
  67. Break;
  68. end;
  69. end;
  70. // A versão abaixo funciona em qualquer Delphi!
  71. procedure GetRecord4(AId: Byte; out AMyRecord: TMyRecord);
  72. var
  73. i: Byte;
  74. begin
  75. ZeroMemory(@AMyRecord,SizeOf(TMyRecord));
  76. for i := 0 to High(MyRecords) do
  77. if MyRecords[i].Id = AId then
  78. begin
  79. AMyRecord := MyRecords[i];
  80. Break;
  81. end;
  82. end;
  83. // A versão abaixo não funciona bem porque tem um parâmetro var que no fim das
  84. // contas é o mesmo que ser uma fução onde usamos a variável Result
  85. procedure GetRecord5(AId: Byte; var AMyRecord: TMyRecord);
  86. var
  87. i: Byte;
  88. begin
  89. ZeroMemory(@AMyRecord,SizeOf(TMyRecord));
  90. for i := 0 to High(MyRecords) do
  91. if MyRecords[i].Id = AId then
  92. begin
  93. AMyRecord := MyRecords[i];
  94. Break;
  95. end;
  96. end;
  97. // Essa forma de limpeza tira proveito do parâmetro out
  98. procedure ClearMyRecord(out AMyRecord: TMyRecord);
  99. begin
  100. ZeroMemory(@AMyRecord,SizeOf(TMyRecord));
  101. end;
  102. // Essa função é idêntica a GetRecords1, mas usa ClearMyRecord e por isso, não gera memory leaks
  103. function GetRecord6(AId: Byte): TMyRecord;
  104. var
  105. i: Byte;
  106. begin
  107. ClearMyRecord(Result);
  108. for i := 0 to High(MyRecords) do
  109. if MyRecords[i].Id = AId then
  110. begin
  111. Result := MyRecords[i];
  112. Break;
  113. end;
  114. end;
  115. var
  116. i: Byte;
  117. begin
  118. ReportMemoryLeaksOnShutdown := True;
  119. // Preenche o array MyRecords com 16 elementos
  120. FillMyRecords(MyRecords);
  121. // Executa GetRecord de 0 a 15. Descomente cada uma das 5 versões
  122. // individualmente para ver os comportamentos
  123. for i := 0 to 15 do
  124. begin
  125. // GetRecord1(i); // Gera Memory Leak
  126. // GetRecord2(i); // Não gera Memory Leak
  127. // GetRecord3(i); // Não gera Memory Leak
  128. // GetRecord4(i,MyRecord); // Não gera Memory Leak
  129. // GetRecord5(i,MyRecord); // Gera Memory Leak
  130. // GetRecord6(i); // Não gera Memory Leak
  131. end;
  132. // Não importa se o primeiro parâmetro é diferente ou igual. Após a execução
  133. // da primeira versão, todas as outras geram ML
  134. // GetRecord5(0,MyRecord); // Não gera Memory Leak
  135. // GetRecord5(1,MyRecord); // Gera Memory Leak (e todas as chamadas subsequentes)
  136. end.
ダウンロード 印刷用表示

このコピペの URL

JavaScript での埋め込み

iframe での埋め込み

元のテキスト