#delphi #delphi-10.4-sydney
#delphi #delphi-10.4-Сидней
Вопрос:
Используя Delphi 10.4.1, я попробовал пользовательское управляемое управление записями для инициализации записи, но все равно получаю утечки памяти.
unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, System.IOUtils, System.DateUtils, System.Character,
Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TForm3 = class(TForm)
Button1: TButton;
RadioGroup1: TRadioGroup;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
type
TMyRec = record
DateTime: TDateTime;
v, size: integer;
str: string;
class operator Initialize (out Dest: TMyRec);
end;
TMyREcHolder = class
data: TMyRec;
constructor Create(const e: TMyRec);
end;
TMyList = class(TList)
procedure Clear; override;
end;
implementation
{$R *.dfm}
class operator TmyRec.Initialize (out Dest: TMyRec);
begin
Dest.str := '';
end;
{ TMyREcHolder }
constructor TMyREcHolder.Create(const e: TMyRec);
begin
inherited Create;
data := e;
end;
{ TMyList }
procedure TMyList.Clear;
var
i: integer;
begin
for i := 0 to Count - 1 do
TMyREcHolder(Items[i]).Free;
inherited Clear;
end;
procedure TForm3.Button1Click(Sender: TObject);
var
lst: TMyList;
i: integer;
rec: TMyRec;
FI: TSearchrec;
begin
Initialize(rec);
lst := TMyList.Create;
try
if FindFirst(TPath.Combine('C:temp', '*.txt'), faAnyFile, FI) = 0 then
begin
repeat
if (FI.FindData.dwFileAttributes and faDirectory = 0) and
(FI.FindData.dwFileAttributes and faArchive = faArchive) then
begin
Application.ProcessMessages;
case RadioGroup1.ItemIndex of
0: Initialize(rec);
1: rec.str := '';
2: fillchar(rec, sizeof(rec), 0);
end;
try
rec.DateTime := FI.TimeStamp;
except
rec.DateTime := EncodeDateDay(1970, 1);
end;
rec.size := FI.size;
rec.str := FI.Name;
lst.Add(TMyREcHolder.Create(rec));
end;
until (FindNext(FI) <> 0);
FindClose(FI);
end;
finally
lst.Free;
end;
end;
end.
Radiogroup предлагает три элемента, как 1, так и 3 утечки памяти. Кто-нибудь может объяснить, почему выполняется инициализация? Мне нужен надежный способ очистки записи, который помог бы мне отучить себя от 20-летней привычки к заполнению.
Комментарии:
1. Разве смысл
Initialize
оператора не в том, что компилятор вызывает его для вас при создании записи? Если вы хотите очистить запись в цикле, сделайтеrec := Default(TMyRec)
. Глядя на ваш код, я думаю, что вы неправильно поняли, чтоInitialize
делает оператор. Похоже, вы считаете, что он может быть вызван вами, когда захотите, но, по крайней мере, насколько я понимаю, он вызывается компилятором, вводящим неявные вызовы, выполняемые при создании записей.2. Да, я просто предположил, что могу использовать функцию записи, когда захочу. Странно, что я не могу ввести пользовательскую функцию, которую я могу просто вызвать (например, в классе). Я хотел использовать документированный оператор. Я понимаю, что Default существует уже давно, но не является официальным. Спасибо, что прояснили это.
3.
Default()
является официальным. Когда вы звонитеInitialize(rec)
, вы звоните не своему оператору. Вы вызываете функцию RTL. И тот, который IIRC, вы не должны вызывать. Поэтому я считаю, что ответ на ваш вопрос по-прежнему заключается в том, что вы должны использоватьrec := Default(...)
вместо своихFillChar
вызовов.4. Другой вопрос, чего вы пытаетесь достичь здесь? строки являются управляемым типом, и они будут автоматически инициализированы в записи. Далее, почему вы храните запись в объекте TMyREcHolder? Если вы уже используете классы, вы можете также поместить все поля в класс. Я бы использовал записи с общим списком TList<TMyRec> и избегал возни с управлением памятью.
5. Да, создайте и используйте понятную процедуру. Использование FillChar для очистки записи является и всегда было проблематичным, когда сохраняется какой-либо управляемый тип, потому что нет возможности выполнить управление (управление выполняется с помощью магии компилятора).