2011-01-12 9 views
3

I die folgende Code-Sequenz haben:Erste Zuordnungsadresse eines Objekts in Delphi 7

program OverrideAfterConstructionEtc; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, Classes; 

type 

TA = class(TInterfacedObject) 
public 
procedure AfterConstruction; override; 
procedure BeforeDestruction; override; 
protected 
FDummyData: array[ 1 .. 1000 ] of longint; 
end; 

{ TA } 

procedure TA.AfterConstruction; 
var 
    selfPtr: Pointer; 
    selfInt: Integer; 
    selfStr: string; 
    size: Integer; 
begin 
    inherited AfterConstruction; 
    selfPtr := Addr(self); 
    selfInt := Integer(selfPtr); 
    selfStr := IntToHex(selfInt, 8); 

    size := TA.InstanceSize; 
    WriteLn('TA instance allocated at 0x', selfStr); 
    WriteLn('TA size is ', size); 


end; 

procedure TA.BeforeDestruction; 
var 
    selfPtr: Pointer; 
    selfInt: Integer; 
    selfStr: string; 

    size: Integer; 

begin 

    selfPtr := Addr(self); 
    selfInt := Integer(selfPtr); 
    selfStr := IntToHex(selfInt, 8); 

    WriteLn('Preparing to destroy TA instance allocated at 0x', selfStr); 

    size := TA.InstanceSize; 
    WriteLn('TA size is ', size); 

    inherited BeforeDestruction; 
end; 

const 
    maxDummy = 1000; 
var 
    a: TA; 
    dummy: TList; 
    iter : integer; 

    dummies: array [ 1 .. maxDummy ] of TList; 
begin 

    // Simulate a set of allocations. 

    for iter := 1 to maxDummy do 
    begin 
     dummy := TList.Create; 
     dummies[ iter ] := dummy; 
    end; 

    // Allocate the object we want to track. 
    a := TA.Create; 

    // Release the simulated allocations. 
    for iter := 1 to maxDummy do 
    begin 
     dummy := dummies[ iter ]; 
     dummies[ iter ] := nil; 
     FreeAndNil(dummy); 
    end; 



    // Release the tracked object. 

    FreeAndNil(a); 

end. 

Die Ausgabe des Codes ist:

  • TA-Instanz bei 0x0012FF88 zugeordnet
  • TA Größe 4012 Vorbereiten zum Zerstören
  • TA-Instanz bei 0x0012FF80
  • TA-Größe ist 4012

Ich verstehe nicht den "Selbst" Unterschied. Kannst du mir einen Hinweis geben? Ich hätte erwartet, dass die gedruckten Werte gleich wären.

Antwort

12

Self in einer Instanzmethode ist ein implizites Argument und ist eine Referenz an die Instanz, die den Methodenaufruf empfangen hat. Es ist als Zeiger implementiert.

Die Addr Standardprozedur ist die gleiche wie die @-Operator; Es nimmt die Adresse des Ortes an, der ihm übergeben wurde. Wenn Sie Addr auf Self anwenden, erhalten Sie die Adresse des Parameterorts nicht die Adresse der Instanz. Diese Parameterposition wird auf dem Stack zugewiesen, da sie nur vorhanden sein muss, während der Methodenaufruf aktiv ist. Wenn der Methodenaufruf zurückkehrt, ist der Speicherplatz für den Parameter Self nicht mehr erforderlich. Es wird implizit durch den Stapelzeiger der CPU freigegeben, der zu dem zurückkehrt, was er vor dem Aufruf der Methode war.

Der Grund, warum der Self-Parameter an verschiedenen Orten in verschiedenen Aufrufen von Methoden auf der gleichen Instanz sein kann, liegt daran, dass mehr oder weniger Daten auf dem Stapel zum Zeitpunkt des Aufrufs vorhanden sein können.Der Parameter Self wird z. B. anders zugeordnet, wenn die Methodenaufruffolge wie A -> B -> C im Vergleich zu A -> C aussieht, da der Stapelrahmen für B zwischen den Stapelrahmen für A und C gespeichert werden muss. Im Stack-Frame werden die Parameter und Locals zugeordnet, die einem bestimmten Aufruf einer Methode zugeordnet sind.

9

Der folgende Code wird Ihnen eine Erklärung geben:

type 
    TA = class(TInterfacedObject) 
    public 
    procedure AfterConstruction; override; 
    procedure BeforeDestruction; override; 
    end; 

procedure TA.AfterConstruction; 
begin 
    inherited; 
    writeln('AfterConstruction=',integer(self)); 
    writeln('AfterConstruction=',integer(addr(self))); 
end; 

procedure TA.BeforeDestruction; 
begin 
    writeln('BeforeDestruction=',integer(self)); 
    writeln('BeforeDestruction=',integer(addr(self))); 
    inherited; 
end; 

Hier die Ausgabe ist:

AfterConstruction=10731904 
AfterConstruction=1245020 
BeforeDestruction=10731904 
BeforeDestruction=1245028 

So integer (Selbst-) korrekt ist (beide Werte gleich 10.731.904), aber integer (Adr (Selbst)) ist nicht.

Weil addr (self) nicht den Eigenwert anzeigt, sondern der Eigenwert gespeichert ist.

In beiden Fällen ist es in dem Stapel (Verwendung von Alt-F2 zu zerlegen das Präfix beiden Methoden) gespeichert:

mov [esp],eax 

wenn Sie Adr (Selbst-) verwenden Also, sind Sie in dem aktuellen Suche Stapeladresse, nicht der Eigenwert.

Addr ist keine einfache Typumwandlung in einen Zeiger, sondern dasselbe wie @self, daher ist die Verwendung von Ganzzahl (self) nicht das Gleiche wie Integer (addr (self)).

Sie sollten Addr (self) aber self nicht verwenden, um die Zuordnungsadresse Ihres Objekts zu finden.

+0

Vielen Dank für Ihre Antworten. Wie markiere ich beide als Antworten (die Web-UI erlaubt mir nur, eine davon auszuwählen)? – Dan

+0

@Dan Ich denke, Sie können nur einen auswählen! Das ist der Deal! :) –