Das Problem ist die Referenz-Zählung für die Strings. Bei jeder Zuweisung wird der String an eine andere Speicheradresse geschrieben und die alte Speicheradresse wird als frei markiert.
Es taucht
nicht auf, wenn man für die Eigenschaften
Name
und
Vorname
einen Getter benutzt
Delphi-Quellcode:
type
TAdresse = class
private
FVorname: string;
FName: string;
function GetName: string;
function GetVorname: string;
public
property Vorname: string read GetVorname write FVorname;
property Name: string read GetName write FName;
end;
Weiterhin taucht es
nicht auf, wenn man die Adresse so zusammensetzt
Delphi-Quellcode:
function TFoo.GetFullName : string;
begin
Result := GetAdresse.Vorname + GetAdresse.Nachname;
end;
Und wenn man sich mal spasseshalber die Pointer auf die Variablen holt
Delphi-Quellcode:
function TTest.GetFullName : string;
var
LVorname, LName : PChar;
begin
LVorname := PChar( GetAdresse.Vorname );
// jetzt zeigt der Debugger den korrekten Vornamen bei LVorname an
LName := PChar( GetAdresse.Name );
// ab jetzt steht in LVorname und LName der gleiche Wert, weil nun die Pointer an die gleiche Stelle zeigen
Result := GetAdresse.Vorname + GetAdresse.Nachname;
end;
Dieses ist aber eher Zufall, da die beiden Speicherstellen abwechselnd belegt werden, was wir mit folgendem Code überprüfen können
Delphi-Quellcode:
function TTest.GetFullName: string;
var
LName1, LVorname, LName2 : PChar;
begin
{1} LName1 := PChar( GetAdresse.Name );
{2} LVorname := PChar( GetAdresse.Vorname );
{3} LName2 := PChar( GetAdresse.Name );
end;
Hier die Inhalte jeweils nach der Codezeile
Nr | LName1 | LVorname | LName2 |
---|
{1} | Lustig | - | - |
{2} | Lustig | Peter | - |
{3} | Peter | Lustig | Lustig |
oder wenn man sich die Pointer-Adressen anschaut, dann (Beispielswerte, die ändern sich eh je nach Start)
Nr | LName1 | LVorname | LName2 |
---|
{1} | $420C | - | - |
{2} | $420C | $422C | - |
{3} | $420C | $422C | $422C |
Oder hier einmal schön den Wechselreigen mit den Adressen bei der Zuweisung
Codezeile | + Adresse | - Adresse |
---|
Adresse.Vorname := 'Peter'; | A | |
Adresse.Name := 'Lustig'; | B | |
Zugriff auf Vorname => A | | |
Adresse.Vorname := 'Peter'; | C | A |
Adresse.Name := 'Lustig'; | A | B |
Zugriff auf Name => A | | |
Adresse.Vorname := 'Peter'; | B | C |
Adresse.Name := 'Lustig'; | C | A |
Der Vollständigkeit halber sei noch erwähnt, dass dieses hier
Delphi-Quellcode:
function TTest.GetFullNameReverse: string;
begin
Result := GetAdresse.Name + ' ' + GetAdresse.Vorname;
end;
natürlich einwandfrei funktioniert. Warum?
Codezeile | + Adresse | - Adresse |
---|
Adresse.Vorname := 'Peter'; | A | |
Adresse.Name := 'Lustig'; | B | |
Zugriff auf Name => B | | |
Adresse.Vorname := 'Peter'; | C | A |
Adresse.Name := 'Lustig'; | A | B |
Zugriff auf Vorname => C | | |
Adresse.Vorname := 'Peter'; | B | C |
Adresse.Name := 'Lustig'; | C | A |
(funktioniert aber auch nur, weil der Speicherbereich noch nicht überschrieben wurde)