1
|
关于TList.Clear释放内存 一直以来被TList.Clear是否会释放每个Item的内存纠结,今天终于找到确切的答案了:不会释放,所以要释放每个Item指向的内存块,还是需要自己老老实实用循环Free掉或者Dispose掉
|
感谢回复。
Clear 只是清除了项中的内容,其中的对象并没销毁。请看DELPHI的实例:
procedure TForm1.FormButton1Click(Sender: TObject);
type
PMyList = ^AList;
AList = record
I: Integer;
C: Char;
end;
var
MyList: TList;
ARecord: PMyList;
B: Byte;
Y: Word;
begin
MyList := TList.Create;
try
New(ARecord);
ARecord^.I := 100;
ARecord^.C := 'Z';
MyList.Add(ARecord); {Add integer 100 and character Z to list}
New(ARecord);
ARecord^.I := 200;
ARecord^.C := 'X';
MyList.Add(ARecord); {Add integer 200 and character X to list}
{ Now paint the items onto the paintbox}
Y := 10; {Variable used in TextOut function}
for B := 0 to (MyList.Count - 1) do
begin
ARecord := MyList.Items[B];
Canvas.TextOut(10, Y, IntToStr(ARecord^.I)); {Display I}
Y := Y + 30; {Increment Y Value again}
Canvas.TextOut(10, Y, ARecord^.C); {Display C}
Y := Y + 30; {Increment Y Value}
end;
{ Cleanup: must free the list items as well as the list }
for B := 0 to (MyList.Count - 1) do
begin
ARecord := MyList.Items[B];
Dispose(ARecord);
end;
finally
MyList.Free;
end;
end;
跟进源码里看看就知道了啊
tstringlist从strings继承,strings 是个抽象类,clear是它的抽象方法,由其子类来负责实现clear,你可以自己覆盖clear,在其中做释放内存的工作,但顾名思义tstringlist只是string的容器,string和intert、double...这些简单类型一样,都是由系统维护它们的引用记录来自动管理其生命周期的,不用人为干预。
tlist的clear是个虚函数。
procedure TList.Clear;
begin // 基类实现中没有且也不应该负责清理item分配的内存
SetCount(0);
SetCapacity(0);
end;
你应该在其析构函数中处理item的内存清理工作,如果你要clear时也清理内存,就上面说的自己重写覆盖clear函数,在里面做清理。
我一般这样子释放:
for m := 0 to ls.Count - 1 do
Dispose(PExit(ls[m]));
ls.Clear();
ls.Free();
如果List里面是指针的话,需要单独释放每个item内容,然后再clear
PExit是自己定义的么。我没找到这个函数的过程。
还有 Dispose 需要指针类型的,直接给结构体导致编译不通过
间接赋值再释放导致出现数据访问错误的问题。。
begin
ARecord := MyList.Items[B];
Dispose(ARecord);-----这里编译器提示 ARecord不是指针类型。delphi 2010的
end;
finally
MyList.Free;
end;
end;
弄个简单的重写Tlist.Clear满足你需求的例子(非泛型,当然泛型更是方便了)
另外俺不是撸大师,请教俺撸同学,要保证鲁棒性必须清晰把握对象的生命周期
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
unit
Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
// 继承Tlist并重写Clear方法
TMyList =
class
(TList)
public
procedure
Clear; override;
end
;
// 自定义个类型做为item,测试用
TMyClass =
class
(TInterfacedObject)
public
FMeb:
Integer
;
end
;
TForm1 =
class
(TForm)
btn1: TButton;
procedure
btn1Click(Sender: TObject);
procedure
FormDestroy(Sender: TObject);
procedure
FormCreate(Sender: TObject);
private
public
end
;
var
Form1: TForm1;
implementation
{
$R
*.dfm}
var
li: TMyList;
procedure
TForm1
.
btn1Click(Sender: TObject);
var
m: TMyClass;
const
{
$J
+} count:
Integer
=
0
; {
$J
-}
begin
m := TMyClass
.
Create;
Inc(count,
1000
);
m
.
FMeb := count;
li
.
Add(m);
// 可以观察到li.count是否正常,且item内容是否正确访问到
Caption := Format(
'li.count=%d; li.items[li.count-1]=%d'
, [li
.
Count, TMyClass(li
.
Items[li
.
Count -
1
]).FMeb]);
//li.Clear; 销毁list所有item, 可去掉注释猛击按钮观察count的值始终为1,且也没有泄露内存
end
;
{ TMyList }
procedure
TMyList
.
Clear;
var
I:
Integer
;
begin
// 倒叙遍历items确保安全访问index
for
I := Count -
1
downto
0
do
begin
// 通过多态销毁item
// 如果想使用 is、as 操作符,得实现Iinterface接口
TMyClass(Items[i]).Free;
end
;
inherited
;
end
;
procedure
TForm1
.
FormCreate(Sender: TObject);
begin
li := TMyList
.
Create;
end
;
procedure
TForm1
.
FormDestroy(Sender: TObject);
begin
li
.
Free;
//销毁list自身,free中会调用析构函数destroy,destroy中调用了clear
end
;
end
.
|
procedure
TForm1
.
FormButton1Click(Sender: TObject);
type
PMyList = ^AList;
AList =
record
I:
Integer
;
C:
Char
;
end
;
var
MyList: TList;
ARecord: PMyList;
B:
Byte
;
Y:
Word
;
begin
MyList := TList
.
Create;
try
New(ARecord);
ARecord^.I :=
100
;
ARecord^.C :=
'Z'
;
MyList
.
Add(ARecord);
{Add integer 100 and character Z to list}
New(ARecord);
ARecord^.I :=
200
;
ARecord^.C :=
'X'
;
MyList
.
Add(ARecord);
{Add integer 200 and character X to list}
{ Now paint the items onto the paintbox}
Y :=
10
;
{Variable used in TextOut function}
for
B :=
0
to
(MyList
.
Count -
1
)
do
begin
ARecord := MyList
.
Items[B];
Canvas
.
TextOut(
10
, Y, IntToStr(ARecord^.I));
{Display I}
Y := Y +
30
;
{Increment Y Value again}
Canvas
.
TextOut(
10
, Y, ARecord^.C);
{Display C}
Y := Y +
30
;
{Increment Y Value}
end
;
{ Cleanup: must free the list items as well as the list }
for
B :=
0
to
(MyList
.
Count -
1
)
do
begin
ARecord := MyList
.
Items[B];
Dispose(ARecord);
end
;
finally
MyList
.
Free;
end
;
end
;
|
我用的是delphi 2010 而且我的 list是泛型的,没有办法那样释放
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
procedure
TForm1
.
FormDestroy(Sender: TObject);
var
I:
Integer
;
begin
// TForm1销毁时 销毁list
if
Assigned(List)
then
begin
for
I := List
.
Count -
1
downto
0
do
begin
FreeMemory(list
.
Items[i]); -------这里提示编译不通过 要求是指针
// FreeAndNil(list); 放到下面
end
;
end
;
FreeAndNil(list);
end
;
这样,即便仅仅create,最后销毁也不会有漏网的
procedure
TForm1
.
FormCreate(Sender: TObject);
var
gl, gl2: pGamelist;
begin
List := TList < pGamelist > .Create;
//gl := GetMemory(SizeOf(TGamelist));
//gl2 := GetMemory(SizeOf(TGamelist));
//gl^.sky := 1000;
//gl2^.sky := 2000;
//List.Add(gl);
// 添加两项
//List.Add(gl2);
end
;
|