Delphi(Win32)中的相互引用记录

Delphi(Win32)中的相互引用记录,delphi,data-structures,Delphi,Data Structures,在Delphi中是否有创建相互引用记录的方法?以下是代码的简化版本: MyRec1 = record arr: MyRec2Array; end; MyRec2 = record mr: MyRec1; end; MyRec2Array = array of MyRec2; 记录类型的正向声明 MyRec2 = record; 在Delphi for Win32中不起作用 切换到类而不是记录是不好的,因为这会增加内存消耗和代码复杂度,所以我宁愿保留记录 有什么建议吗?记录是值类型

在Delphi中是否有创建相互引用记录的方法?以下是代码的简化版本:

MyRec1 = record
  arr: MyRec2Array;
end;

MyRec2 = record
  mr: MyRec1;
end;

MyRec2Array = array of MyRec2;
记录类型的正向声明

MyRec2 = record;
在Delphi for Win32中不起作用

切换到类而不是记录是不好的,因为这会增加内存消耗和代码复杂度,所以我宁愿保留记录


有什么建议吗?

记录是值类型,而不是引用类型。这意味着作为更大数据结构的成员使用的所有记录都内联放置在结构本身中,而不是作为指针。试图创建两条相互包含的记录会使编译器在试图找出记录的结构时陷入无限循环。这可能就是为什么不能向前声明记录的原因,即使尝试在此处插入引用类型(动态数组),也不能违反语言规则

但您可以将指向记录类型的指针声明为转发声明,如下所示:

PMyRec2 = ^MyRec2
...
MyRec2 = record
  ...
end;
当然,一旦您开始使用指向记录的指针,您就必须担心分配和释放内存,并且您试图通过不使用类来避免的代码复杂性会出现在您的项目中。底线:对类执行此操作。将其中一条记录(如果不是两条记录)制作为一个类。这是最简单的方法,真的


而且额外的内存开销可以忽略不计。对于每个引用,它指向一个指向对象的指针,不管怎样,指向对象的指针都需要这个指针,加上D2009之前的每个实例一个隐藏字段(4字节),或者D2009或更高版本上的两个隐藏字段(8字节)。这一点也不算多。

虽然我完全同意梅森的观点,但有一种方法可以绕过这个限制。基本上,在声明MyRec2之后,您可以使用记录助手来定义必要的功能

type
  MyRec1 = record
    arr: array of byte;
  end;

  MyRec2 = record
    mr: MyRec1;
  end;

  MyRec1Helper = record helper for MyRec1
    procedure AllocateMyRec2(numItems: integer);
    function  GetMyRec2(i: integer): MyRec2;
    procedure SetMyRec2(i: integer; const value: MyRec2);
    property Rec2[i: integer]: MyRec2 read GetMyRec2 write SetMyRec2;
  end;

procedure MyRec1Helper.AllocateMyRec2(numItems: integer);
begin
  SetLength(arr, numItems * SizeOf(myRec2));
end;

function MyRec1Helper.GetMyRec2(i: integer): MyRec2;
begin
  Move(arr[i*SizeOf(MyRec2)], Result, SizeOf(MyRec2));
end;

procedure MyRec1Helper.SetMyRec2(i: integer; const value: MyRec2);
begin
  Move(value, arr[i*SizeOf(MyRec2)], SizeOf(MyRec2));
end;

var
  my: MyRec2;

begin
  my.mr.AllocateMyRec2(2);
  my.mr.Rec2[0].mr.AllocateMyRec2(3);
end.

这个问题对我来说就像一个笑话——它不是关于相互引用,而是关于无限类型定义循环。至于相互引用,可以通过在记录中定义类型来解决(我使用了Delphi 2009):

但如何使用上述记录类型?真有趣。:)


可能重复:这毫无意义。如果我们假设每个MyRec2Array的长度是固定的且非零,那么您正试图创建一个占用无限多字节的数据结构…@Andreas Rejbrand-MyRec2Array是动态数组。@Alexander:我知道。这就是我为什么写“如果我们假设……”的原因。安德烈亚斯·雷杰布兰德,这个假设有什么意义?用类替换记录-不会有任何更改,除非编译器允许。在实践中,许多mr提到值类型的后果时都是零+1,而使用指针指针解决方法正是我所寻找的。我还认为TObject的每个实例大约占用30个字节。我不知道我从哪里得到的,但在读了你的帖子后,我在D2007中切掉了它,它实际上是4个字节。所以你是绝对正确的。谢谢!请注意,值类型限制在此不适用,因为dynarray已经是动态类型。这可能就是为什么“serg”的变通方法有效。
type
  MyRec2 = record
  type
    MyRec2Array = array of MyRec2;
  type
    MyRec1 = record
      arr: MyRec2Array;
    end;
  var
    mr: MyRec1;
  end;
procedure TForm1.Button1Click(Sender: TObject);
var
  R: MyRec2;

begin
  SetLength(R.mr.arr, 1);
//  R.mr.arr[0]:= ???;
end;