- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在研究 Sergey Antonov 的智能指针示例,请参阅:http://blog.barrkel.com/2008/11/reference-counted-pointers-revisited.html (评论中的某处)。
SSCCE:
program TestSmartPointer;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
TInjectType<T> = record
public
VMT: pointer;
unknown: IInterface;
RefCount: integer;
AValue: T;
end;
TInject<T> = class
public type
TInjectType = TInjectType<T>;
PInjectType = ^TInjectType;
end;
PInjectObjectType = TInject<TObject>.PInjectType;
TSmartPointer<T: class> = class
class function Wrap(const AValue: T): TFunc<T>; static;
end;
function Trick_Release(const obj: PInjectObjectType): Integer; stdcall; forward;
function Trick_AddRef(const obj: PInjectObjectType): Integer; stdcall; forward;
function Invoke(var obj): TObject; forward;
const
PSEUDO_VMT: array [0 .. 3] of pointer = (nil, @Trick_AddRef, @Trick_Release, @Invoke);
function Trick_AddRef(const obj: PInjectObjectType): Integer; stdcall;
begin
Result:= AtomicIncrement(Obj^.RefCount);
end;
function Trick_Release(const obj: PInjectObjectType): Integer; stdcall;
begin
Result:= AtomicDecrement(Obj^.RefCount);
if Result = 0 then obj^.AValue.Free;
end;
function Invoke(const obj: PInjectObjectType): TObject;
begin
Result:= obj^.AValue;
end;
class function TSmartPointer<T>.Wrap(const AValue: T): TFunc<T>;
var
h: TInjectType<T>;
begin
h.RefCount:= 1;
pointer(h.unknown):= @h;
h.VMT:= @PSEUDO_VMT;
h.AValue:= AValue;
//Alternative A, this fails
Result:= TFunc<T>(@h);
Inc(h.RefCount);
////Alternative B, this works
//Result:= function: T
// begin
// Result:= h.AValue;
// end;
end;
type
TTestObject = class(TObject)
procedure Test;
destructor Destroy; override;
end;
{ TTestObject }
procedure TTestObject.Test;
begin
WriteLn('Test');
end;
destructor TTestObject.Destroy;
begin
WriteLn('Free');
inherited;
end;
procedure Test;
var
TestObject: TFunc<TTestObject>;
begin
TestObject:= TSmartPointer<TTestObject>.Wrap(TTestObject.Create);
TestObject.Test;
ReadLn; //Works up to this point.
<<<--- generates a AV here.
end;
begin
WriteLn('Start');
Test;
WriteLn('End');
ReadLn;
end.
巴里·凯利解释说:
TFunc = reference to function: T;
is directly equivalent to:
TFunc = interface function Invoke: T; end;
except that locations of a method reference type are assignable using values of a function, method or anonymous method.
Anonymous methods are implemented as interfaces that look just like the method reference, on a hidden class. Location capture is implemented as moving (for locals) and copying (for parameters) to fields on the hidden class. Any accesses of captured locations in the body of the main procedure are converted to access the fields on the hidden class; a local variable, called $frame, points to an instance of this hidden class.
目标
我想优化智能指针的创建。
为了做到这一点,我手工制作了 VMT 并使用它来模拟界面。
如果我像这样定义我的 wrap
函数:
class function TSmartPointer<T>.Wrap(const AValue: T): TFunc<T>;
var
h: TInjectType<T>;
begin
pointer(h.unknown):= @h;
h.VMT:= @PSEUDO_VMT;
h.AValue:= AValue;
Result:= function: T
begin
Result:= h.AValue;
end;
end;
一切正常。
如果我将其优化为:
class function TSmartPointer<T>.Wrap(const AValue: T): TFunc<T>;
var
h: TInjectType<T>;
begin
h.RefCount:= 1;
pointer(h.unknown):= @h;
h.VMT:= @PSEUDO_VMT;
h.AValue:= AValue;
//Alternative A, this fails
Result:= TFunc<T>(@h);
Inc(h.RefCount);
end;
它几乎可以工作,但是一旦调用函数关闭就会给出一个AV。
procedure Test;
var
TestObject: TFunc<TTestObject>;
begin
TestObject:= TSmartPointer<TTestObject>.Wrap(TTestObject.Create);
TestObject.Test;
ReadLn;
//Works up to this point.
<<<--- generates a AV here.
end;
您希望 AV 出现在 _Release 中,但事实并非如此,事实上,它会发生在 _Release 之前。
TestNewStringHelper.dpr.98: TestObject.Test;
00419F0B 8B45FC mov eax,[ebp-$04]
此处EAX = 0018FF40
00419F0E 8B10 mov edx,[eax]
00419F10 FF520C call dword ptr [edx+$0c]
00419F13 E82CFFFFFF call TTestObject.Test
TestNewStringHelper.dpr.100: end;
00419F18 33C0 xor eax,eax
00419F1A 5A pop edx
00419F1B 59 pop ecx
00419F1C 59 pop ecx
00419F1D 648910 mov fs:[eax],edx
00419F20 68359F4100 push $00419f35
00419F25 8D45FC lea eax,[ebp-$04]
这里EAX = 0018FF6C
显然应该和之前一样。事实上,事实并非如此,这就是接下来的 AV 的原因:
00419F28 E87BF6FEFF call @IntfClear <<-- AV
调用IntfClear
AV,因为它无法为_Release
找到合适的目标。 IOW,调用永远不会到达_Release,而是跳转到未知。
System.pas.36036: MOV EDX,[EAX]
004095A8 8B10 mov edx,[eax]
System.pas.36037: TEST EDX,EDX
004095AA 85D2 test edx,edx
System.pas.36038: JE @@1
004095AC 740E jz $004095bc
System.pas.36039: MOV DWORD PTR [EAX],0
004095AE C70000000000 mov [eax],$00000000
System.pas.36043: PUSH EAX
004095B4 50 push eax
System.pas.36044: PUSH EDX
004095B5 52 push edx
System.pas.36045: MOV EAX,[EDX]
004095B6 8B02 mov eax,[edx]
System.pas.36046: CALL DWORD PTR [EAX] + VMTOFFSET IInterface._Release
004095B8 FF5008 call dword ptr [eax+$08] <<-- AV here
为什么要这样做?我需要进行哪些调整才能使优化版本正常工作?
最佳答案
有效的代码捕获局部变量h
。这意味着它的使用生命周期延长了。编译器通过在堆上分配变量 h
来实现这一点。
您的代码没有任何变量捕获。这意味着 h
被分配在堆栈上,并且它的生命周期在函数返回时结束。因此,您对 h
的后续引用无效。
关于delphi - 为什么智能指针的这种优化不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30153682/
我刚接触 C 语言几周,所以对它还很陌生。 我见过这样的事情 * (variable-name) = -* (variable-name) 在讲义中,但它到底会做什么?它会否定所指向的值吗? 最佳答案
我有一个指向内存地址的void 指针。然后,我做 int 指针 = void 指针 float 指针 = void 指针 然后,取消引用它们以获取值。 { int x = 25; vo
我正在与计算机控制的泵进行一些串行端口通信,我用来通信的 createfile 函数需要将 com 端口名称解析为 wchar_t 指针。 我也在使用 QT 创建一个表单并获取 com 端口名称作为
#include "stdio.h" #include "malloc.h" int main() { char*x=(char*)malloc(1024); *(x+2)=3; --
#include #include main() { int an_int; void *void_pointer = &an_int; double *double_ptr = void
对于每个时间步长,我都有一个二维矩阵 a[ix][iz],ix 从 0 到 nx-1 和 iz 从 0 到 nz-1。 为了组装所有时间步长的矩阵,我定义了一个长度为 nx*nz*nt 的 3D 指针
我有一个函数,它接受一个指向 char ** 的指针并用字符串填充它(我猜是一个字符串数组)。 *list_of_strings* 在函数内部分配内存。 char * *list_of_strings
我试图了解当涉及到字符和字符串时,内存分配是如何工作的。 我知道声明的数组的名称就像指向数组第一个元素的指针,但该数组将驻留在内存的堆栈中。 另一方面,当我们想要使用内存堆时,我们使用 malloc,
我有一个 C 语言的 .DLL 文件。该 DLL 中所有函数所需的主要结构具有以下形式。 typedef struct { char *snsAccessID; char *
指针, C语言的精髓 莫队先咕几天, 容我先讲完树剖 (因为后面树上的东西好多都要用树剖求 LCA). 什么是指针 保存变量地址的变量叫做指针. 这是大概的定义, 但是Defad认为
我得到了以下数组: let arr = [ { children: [ { children: [], current: tru
#include int main(void) { int i; int *ptr = (int *) malloc(5 * sizeof(int)); for (i=0;
我正在编写一个程序,它接受一个三位数整数并将其分成两个整数。 224 将变为 220 和 4。 114 将变为 110 和 4。 基本上,您可以使用模数来完成。我写了我认为应该工作的东西,编译器一直说
好吧,我对 C++ 很陌生,我确定这个问题已经在某个地方得到了回答,而且也很简单,但我似乎找不到答案.... 我有一个自定义数组类,我将其用作练习来尝试了解其工作原理,其定义如下: 标题: class
1) this 指针与其他指针有何不同?据我了解,指针指向堆中的内存。如果有指向它们的指针,这是否意味着对象总是在堆中构造? 2)我们可以在 move 构造函数或 move 赋值中窃取this指针吗?
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: C : pointer to struct in the struct definition 在我的初学者类
我有两个指向指针的结构指针 typedef struct Square { ... ... }Square; Square **s1; //Representing 2D array of say,
变量在内存中是如何定位的?我有这个代码 int w=1; int x=1; int y=1; int z=1; int main(int argc, char** argv) { printf
#include #include main() { char *q[]={"black","white","red"}; printf("%s",*q+3); getch()
我在“C”类中有以下函数 class C { template void Func1(int x); template void Func2(int x); }; template void
我是一名优秀的程序员,十分优秀!