2011-01-12 16 views
3

我有以下代碼序列:在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. 

代碼的輸出:

    在0x0012FF88分配
  • TA實例
  • TA大小是4012準備銷燬
  • 在0x0012FF80處分配的TA實例
  • TA大小爲4012

我不明白「自我」的差異。你能給我一個提示嗎?我本來期望的印刷值是相同的。

回答

12

Self在實例方法中是隱式參數,並且是參考到接收方法調用的實例。它被實現爲一個指針。

Addr標準程序與@操作符相同;它需要傳遞給它的位置的地址。當您將Addr應用於Self時,您將獲取參數位置的地址,而不是實例的地址。該參數位置在堆棧上分配,因爲只有在方法調用處於活動狀態時它才需要存在;當方法調用返回時,不再需要參數Self的空間;它被CPU的堆棧指針隱式地釋放,回到調用該方法之前的任何東西。

Self參數可能位於同一實例上不同調用方法的不同位置的原因是因爲在調用時堆棧中的數據可能會更多或更少。例如,如果方法調用序列看起來像A -> B -> C而不是A -> C,那麼Self參數將被不同地分配,因爲B的堆棧幀需要存儲在AC的堆棧幀之間。堆棧幀是分配與任何給定的方法調用關聯的參數和本地值的位置。

9

下面的代碼會給你一個解釋:

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; 

這裏是輸出:

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

所以整數(個體經營)是正確的(這兩個值等於10731904),但整數(地址(自我))不是。

因爲addr(self)沒有顯示自我價值,而是存儲了自我價值。

在這兩種情況下,它存儲在堆棧(可使用Alt-F2拆解兩種方法的前綴):

mov [esp],eax 

所以,當你使用地址(個體經營),你看當前堆棧地址,而不是自己的價值。

Addr不是一個指針的簡單類型轉換,而是與@self相同,所以使用integer(self)與integer(addr(self))不是一回事。

您不應該使用Addr(self),而是使用self來查找對象的分配地址。

+0

謝謝你的回答。我如何將它們都標記爲答案(Web UI只允許我選擇其中之一)? – Dan 2011-01-13 07:23:43

相關問題