我有下面的代码序列:
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.
代码的输出为:
- TA示例分配在0x0012FF88
- TA大小为4012准备销毁
- TA示例分配在0x0012FF80
- TA大小为4012
我不明白"自我"的区别。你能给我一个提示吗?我本来期望打印的值是一样的。
2条答案
按热度按时间xoefb8l81#
示例方法中的
Self
是一个隐式参数,是对接收方法调用的示例的引用。它被实现为指针。Addr
标准过程与@
运算符相同;它获取传递给它的位置的地址。当你把Addr
应用到Self
时,你得到的是参数位置的地址,而不是示例的地址。这个参数位置在堆栈上分配,因为它只需要在方法调用活动时存在;当方法调用返回时,不再需要用于Self
参数的空间;通过CPU的堆栈指针返回到调用该方法之前的位置,它被隐式地释放。Self
参数在同一示例上的不同方法调用中可能位于不同位置的原因是,调用时堆栈上的数据可能更多或更少。例如,如果方法调用序列看起来像A -> B -> C
与A -> C
,则Self
参数的分配将不同。因为B
的堆栈帧需要存储在A
和C
的堆栈帧之间。堆栈帧是分配与方法的任何给定调用相关联的参数和局部变量的地方。koaltpgm2#
下面的代码将给你一个解释:
下面是输出:
因为addr(self)没有显示self的值,而是显示了self值的存储位置。
在这两种情况下,它都存储在堆栈中(使用Alt-F2反汇编两个方法的前缀):
所以当你使用addr(self)的时候,你看到的是当前的堆栈地址,而不是self的值。
Addr不是简单的指针类型转换,而是和@self一样,所以使用integer(self)和使用integer(addr(self))不一样。
不应该使用Addr(self)而应该使用self来查找对象的分配地址。