Bu çok Delphi'ye özgü bir sorudur (belki de Delphi 2007'ye özgü). Şu anda dizeleri tutmak için basit bir StringPool sınıfı yazıyorum. İyi bir küçük kodlayıcı olarak ben de ünite testleri ekledim ve beni şaşırtan bir şey buldum. Zaten varsa FList sıralanır bir TStringList, bu nedenle tüm kod listesinde dizeyi bakıyor yapar ve: gerçekten fanteziBu dize neden referans sayısı 4? (Delphi 2007)
function TStringPool.Intern(const _s: string): string;
var
Idx: Integer;
begin
if FList.Find(_s, Idx) then
Result := FList[Idx]
else begin
Result := _s;
if FMakeStringsUnique then
UniqueString(Result);
FList.Add(Result);
end;
end;
Hiçbir şey:
Bu
staj kodudur varolan dizeyi döndürür. Henüz listede bulunmuyorsa, önce 1 referans sayısını sağlamak ve daha sonra listeye eklemek için UniqueString'i çağırır. (Ben Sonuç başvuru sayısı kontrol ve beklendiği gibi 'merhaba', iki kez eklendikten sonra 3 içindir.)Şimdi test koduna:
procedure TestStringPool.TestUnique;
var
s1: string;
s2: string;
begin
s1 := FPool.Intern('hallo');
CheckEquals(2, GetStringReferenceCount(s1));
s2 := s1;
CheckEquals(3, GetStringReferenceCount(s1));
CheckEquals(3, GetStringReferenceCount(s2));
UniqueString(s2);
CheckEquals(1, GetStringReferenceCount(s2));
s2 := FPool.Intern(s2);
CheckEquals(Integer(Pointer(s1)), Integer(Pointer(s2)));
CheckEquals(3, GetStringReferenceCount(s2));
end;
Bu dizeyi 'merhaba' ekler dize havuzu iki kez ve dizenin referans sayısını ve ayrıca s1 ve s2'nin aynı dize tanımlayıcısını işaret ettiğini kontrol eder.
Her CheckEquals beklendiği gibi çalışır ancak sonuncudur. "Beklenen: < 3> hatasıyla başarısız olur, ancak: < 4>" idi.
Peki, neden referans sayısı 4 burada? Ben 3 beklerdik:
- s1
- s2
- ve StringList
başka bir Bu Delphi 2007 ve dizeleri nedenle AnsiStrings vardır.
plongword(integer(pointer(s2))-8)^
Sadece görünüyor (Serg gelen cevaba eklemek için: Aynı olarak değerlendirilebilir ayıklayıcıya olarak
function GetStringReferenceCount(const _s: AnsiString): integer;
var
ptr: PLongWord;
begin
ptr := Pointer(_s);
if ptr = nil then begin
// special case: Empty strings are represented by NIL pointers
Result := MaxInt;
end else begin
// The string descriptor contains the following two longwords:
// Offset -1: Length
// Offset -2: Reference count
Dec(Ptr, 2);
Result := ptr^;
end;
end;
: olarak
Ah evet, fonksiyon StringReferenceCount uygulanır % 100 doğru olması için):
Daha sonras3 := FPool.Intern(s2);
s2 := '';
ile
s2 := FPool.Intern(s2);
s3 referans sayısını kontrol (ve s 1), beklendiği gibi bu 3'tür. Bu, FPool.Intern (s2) sonucunu tekrar s2'ye atamaktan (s2, hem parametre hem de işlev sonucunun hedefi) bu fenomene neden oluyor. Delphi, sonucu atamak için gizli bir dize değişkeni sunar.
Ayrıca, bir prosedüre işlevini değiştirirseniz:
procedure TStringPool.Intern(var _s: string);
başvuru sayısı hiçbir gizli değişken gereklidir çünkü beklendiği gibi 3'tür.vaka kimseye yılında
bu TStringPool uygulanmasında ilgilenmektedir: https://sourceforge.net/p/dzlib/code/HEAD/tree/dzlib/trunk/src/u_dzStringPool.pas
Ama
söyledi: O da dzchart parçası olan dzlib, bir parçası olarak açık MPL altında kaynak ve kullanılabilir yukarıda: Tam olarak roket bilimi değildir. ;-)
TestUnique'in sonunda S1 için ref sayısını kontrol edebilir misiniz? Ref sayısının bu noktada ne olduğunu merak ediyorum. –
kesinlikle tahmincilerden saçmalık almak için debug dcus –
+ kullanabilirsiniz. –