我有以下代码序列:
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.
Run Code Online (Sandbox Code Playgroud)
代码的输出是:
我不明白"自我"的区别.你能给我一个提示吗?我原以为打印值是一样的.
Bar*_*lly 13
Self在实例方法中,是一个隐式参数,它是对接收方法调用的实例的引用.它被实现为指针.
所述Addr标准程序是一样的@操作者; 它需要传递给它的位置的地址.申请Addr时Self,您将获取参数位置的地址,而不是实例的地址.此参数位置在堆栈上分配,因为它只需要在方法调用处于活动状态时存在; 当方法调用返回时,不再需要Self参数的空间; 它被隐式释放,由CPU的堆栈指针移回到调用方法之前的状态.
Self参数可能位于同一实例上的方法的不同调用中的不同位置的原因是因为在调用时堆栈上可能存在更多或更少的数据.例如,Self如果方法调用序列看起来像是A -> B -> C对,则参数将被不同地分配A -> C,因为堆栈帧B需要存储在堆栈帧之间A和C.堆栈帧是分配与方法的任何给定调用相关联的参数和本地的位置.
Arn*_*hez 11
以下代码将为您解释:
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;
Run Code Online (Sandbox Code Playgroud)
这是输出:
AfterConstruction=10731904
AfterConstruction=1245020
BeforeDestruction=10731904
BeforeDestruction=1245028
Run Code Online (Sandbox Code Playgroud)
所以整数(self)是正确的(两个值都等于10731904),但是整数(addr(self))不是.
因为addr(self)不显示自身值,而是存储自身值.
在这两种情况下,它都存储在堆栈中(使用Alt-F2来反汇编两种方法的前缀):
mov [esp],eax
Run Code Online (Sandbox Code Playgroud)
因此,当您使用addr(self)时,您正在查看当前堆栈地址,而不是自身值.
Addr不是指针的简单类型转换,但与@self相同,因此使用整数(self)与整数(addr(self))不同.
您不应该使用Addr(self)而是self来查找对象的分配地址.