Il arrive qu’on associe un TList, ou un TListView à une chaine string la méthode la plus simple pour associer :
Pour désassocier
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 P:=nil; string(P):=S; List.Add(P);voici quatre versions de fonctions pour le même but ,les trois premières fonctions sont un peu pénalisées dans les applications non multithreadées par le LOCK imposé par le compteur de références.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 P:=List[0]; List[0]:=nil; string(P):='';Utilisation :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 {version 1} function DynAddRef_V1(const AInp:string):Pointer; asm JMP System.@LStrAddRef end; procedure DynRelease_V1(var P: Pointer); asm JMP System.@LStrClr end; {version2} function DynAddRef_V2(const AInp:string):Pointer; begin result:=nil; string(result):= AInp; end; procedure DynRelease_V2(P: Pointer); begin string(P):= ''; end; {version 3} function DynAddRef_V3(AInp:string):Pointer; begin Result:=Pointer(AInp); Pointer(AInp):=nil; end; procedure DynRelease_V3(P: Pointer); var S:string; begin Pointer(S):=P; end; {version 4} function DynAddRef_V4(const AInp:string):Pointer; var P:PInteger; begin result:=Pointer(AInp); if Assigned(result) then begin P := Result; dec(P,2); if (P^ >= 0) then begin if IsMultiThread then Interlockedincrement(P^) else inc(P^); end; end; end; procedure DynRelease_V4(var P: Pointer); var PStr:PInteger; begin PStr :=P; if Assigned(PStr) then begin P := nil; dec(PStr,2); if (PStr^ > 0)then begin if IsMultiThread then Interlockeddecrement(PStr^) else dec(PStr^); if PStr^ = 0 then begin Freemem(PStr); end; end; end; end;
Résultat de tests pour différentes versions
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 {association} S:=StringOfchar('a',10); List.Add(DynAddRef_V4(S)); {désassociation} P:=List[0]; List[0]:=nil; DynRelease_V4(P);
DynAddRef_V1/DynRelease_V1-> 1156 ms
DynAddRef_V2/DynRelease_V2 -> 2000 ms
DynAddRef_V3/DynRelease_V3 -> 1578 ms
DynAddRef_V4/DynRelease_V4 -> 140 ms
Exemples sur le compteur de reférences:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 procedure TForm1.Button1Click(Sender: TObject); var P:Pointer; i:integer; sc:string; G:cardinal; begin sc :=StringOfChar(#32,$80); G := GetTickCount; for i := 1 to 8000000-1 do begin P:= DynAddRef_V4(sc); DynRelease_V4(P); end; Showmessagefmt('RefCnt = %d : %d ms',[PInteger(Integer(sc)-8)^,GetTickCount - G]); end;
Exemple1Exemple2
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 var S:string; {variable sur quatre octets } P:Pointer; {variable sur quatre octets } begin {ne faites pas des tests avec des constants du genre S:="azertyu" } {le compteur de références et toujours a -1 qui indique que la chaine } {ne sera jamais libérée } S:=StringOfChar('A',$20); { RefCount = 1} {Le Pointeur P doit contenir une valeur corrècte 'un pointeur sur une chaine'} { ou un nil, Delphi va essayer de decrementer l'ancienne réference ou la libérer} P:=nil; {Le Pointeur P vaut S et le compteur de références est incrementé} {affectation string les compteurs de références sur les deux coté} {sont controlés} string(P):=S; { RefCount = 2} List.Add(P); { end;} { Fin de procedure S n'est pas null le compilo va decrementer le compteur de références } { RefCount = 1 le compteur n'est pas null donc la chaine n'est pas libérée} { le pointeur sur la list est valide } end;Exemple 3
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 var S:string; P:Pointer; begin S:=StringOfChar('A',$20); { RefCount = 1} {Le Pointeur P vaut S et le compteur de références n'est pas incrementé} {S est considéré comme Pointeur et pas comme string ,on a trompé le compilo +-} {affectation Pointeur} P:=Pointer(S); { RefCount = 1} List.Add(P); {S est une variable sur quatre octets pour mettre un nil ou un zéro} Pointer(S):=nil; {ou simplement Integer(S):=0; } { end;} { Fin de procedure S est null rien se passe} { RefCount = 1 le compteur n'est pas null donc la chaine n'est pas libérée} { le pointeur sur la list est valide } end;Pour terminer le compteur de references n'est que le poiteur utilisé par Freemem pour libérer la chaine à Pointer(S) -12 (avec le gestionaire de memoire par défaut)on trouve sa taille en octets
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 var S:string; P:Pointer; begin S:=StringOfChar('A',$20); { RefCount = 1} {Le Pointeur P vaut S et le compteur de références n'est pas incrementé} P:=Pointer(S); { RefCount = 1} List.Add(P); { end;} { Fin de procedure S n'est pas null on decremente le compteur de références} { RefCount = 0 le compteur est null la chaine est libérée} { le pointeur sur la list n'est pas valide {une violation d'accsses} end;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 S:=StringOfChar(#32,128); {PInteger(Integer(S)-12)^ and not cFlags - SizeOf(TUsed)} {Affiche 140} Showmessagefmt('Size = %d',[PInteger(Integer(S)-12)^ and $7FFFFFFC -4]); {on a la chaine string + #0 + 8 octets pour enregister le longueur } {de la chaine et le compteur de réferences} {128 + 1 + 8 = 137 alignés sur 4 = 140}
Partager