为什么编译器坚持我的函数是内联的,而实际上它不是?

2023-12-31

为什么我得到

[DCC 错误] ProjectCOWArray.dpr(23): E2426 内联函数不能有 asm 块

program ProjectCOWArray;

{$APPTYPE CONSOLE}

{$R *.res}

type
  PRefCount = ^TRefCount;
  TRefCount = array[0..1] of integer;


  TCOWArray<T> = record
  private
    fData: TArray<T>;
  private
    procedure IncRefCount;  <<-- not inline  
  end;


{ TCOWArray<T> }

procedure TCOWArray<T>.IncRefCount;
asm
  {$if defined(win32)}
  mov eax,fData;
  lock inc dword ptr [eax - 8];
  {$ifend}
  {$if defined(win64)}
  mov rax,fData;
  lock inc dword ptr[rax -12];
  {$ifend}
end;

begin
end.

德尔福XE2没有AtomicIncrement,那么我该如何解决这个问题呢?
它想保留汇编器,因为否则我无法拥有lock前缀 in 并且我不想使用InterlockedIncrement因为那是一个 WinAPI 函数,我不想要那种开销。


这是因为泛型功能是在内联引擎之上实现的。适用于内联函数的相同限制也适用于泛型函数。编译器编写者只是没有采取额外的步骤来使错误消息特定于泛型而不是内联函数。

我认为调用InterlockedIncrement对于没有AtomicIncrement固有的。或者,创建您自己的版本AtomicIncrement,仅在不包含它的 Delphi 版本中定义。该函数可以用 asm 编写。嗯,显然必须用 asm 编写。

{$IFNDEF AtomicFunctionsAvailable}
function AtomicIncrement(var Target: Integer): Integer;
asm
  ....
end;
{$ENDIF}

或者正如@TLama建议的那样,你可以使用TInterlocked来自System.SyncObjs提供原子操作的单元。

话虽如此,我认为没有必要以这种方式干预内部结构。通过调用实现写数组的副本SetLength(...)每当你写入数组时。例如,这是一个非常简单的写数组复制实现:

unit COWArray;

interface

type
  TCOWArray<T> = record
  private
    FItems: TArray<T>;
    function GetLength: Integer;
    procedure SetLength(Value: Integer);
    function GetItem(Index: Integer): T;
    procedure SetItem(Index: Integer; const Value: T);
  public
    class function New(const Values: array of T): TCOWArray<T>; static;
    property Length: Integer read GetLength write SetLength;
    property Items[Index: Integer]: T read GetItem write SetItem; default;
  end;

implementation

function TCOWArray<T>.GetLength: Integer;
begin
  Result := System.Length(FItems);
end;

procedure TCOWArray<T>.SetLength(Value: Integer);
begin
  System.SetLength(FItems, Value); // SetLength enforces uniqueness
end;

function TCOWArray<T>.GetItem(Index: Integer): T;
begin
  Result := FItems[Index];
end;

procedure TCOWArray<T>.SetItem(Index: Integer; const Value: T);
begin
  System.SetLength(FItems, System.Length(FItems)); // SetLength enforces uniqueness
  FItems[Index] := Value;
end;

class function TCOWArray<T>.New(const Values: array of T): TCOWArray<T>;
var
  i: Integer;
begin
  System.SetLength(Result.FItems, System.Length(Values));
  for i := 0 to high(Values) do
    Result.FItems[i] := Values[i];
end;

end.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么编译器坚持我的函数是内联的,而实际上它不是? 的相关文章

随机推荐