delphi – 使用作为泛型类型数组的类成员进行奇怪的类实例大小调整

前端之家收集整理的这篇文章主要介绍了delphi – 使用作为泛型类型数组的类成员进行奇怪的类实例大小调整前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
下面是一个非常简单的代码,它模仿我的一些代码中的类结构(表单只包含一个附加到click事件的按钮).我正在使用Delphi XE和XE II,并在销毁此类所基于的生产代码中的对象时看到令人讨厌的崩溃.仅当我允许在Clear()方法中初始化TMyClass中的数组项的成员时,才会发生这些崩溃.

不幸的是,到目前为止,在此示例代码中崩溃是不可重复的,但它确实模仿了一些非常奇怪的行为,我怀疑这可能是导致问题的原因.

如果我在TMyClass.Clear函数中放置一个断点并查看类报告1288的InstanceSize成员.这很奇怪,因为单独的数组成员的大小实际上是12kb.我可以将从TRecord2提供的类型更改为Integer,并获得相同的InstanceSize结果.如果我从类中完全删除数组,我得到的实例大小约为264字节,对于只包含一个128字节记录实例的类来说,这似乎是顶部.这表明编译器已为TMyClass中的V(TT类型)成员的数组存储分配了1024个字节.

我怀疑当我将12kb数据写入编译器认为大小为1kb的对象时,奇怪的实例大小会导致不良事件发生.

unit Unit1;

interface

uses
  Winapi.Windows,Winapi.Messages,System.SysUtils,System.Variants,System.Classes,Vcl.Graphics,Vcl.Controls,Vcl.Forms,Vcl.Dialogs,Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TRecord = record A : Array[1..128] of byte; end;
  TRecord2 = packed record S : Single; T : TDateTime; end;

  TBase = class(TObject)
    public
      R : TRecord;
  end;

  TBase2<T> = class(TBase)
    public
      type
        TT = packed array [0..31,0..31] of T;

      var
        V : TT;
        R2 : TRecord;
  end;

  TMyClass = class(TBase2<TRecord2>)
    public
      procedure Clear;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  O : TMyClass;
begin
  O := TMyClass.Create;
  O.Clear;
  O.Free;
end;

{ TMyClass }

procedure TMyClass.Clear;
var
  i,j : integer;
begin
  for i := 0 to 31 do
    for j := 0 to 31 do
      begin
        V[I,J].S := 0;
        V[I,J].T := 0;
      end;
end;

end.@H_301_9@

解决方法

这是一个错误,正如这个最小的再现所示:
program InstanceSizeBug;

{$APPTYPE CONSOLE}

type
  TMyClass<T> = class
    V: array [0..255] of T;
  end;
  TMyClassSingle = class(TMyClass<Single>);

begin
  Writeln(TMyClass<Single>.InstanceSize);
  Writeln(TMyClassSingle.InstanceSize);
  Readln;
end.@H_301_9@ 
 

输出

1032
264@H_301_9@ 
 

请注意,在Delphi 2010中可以观察到相同的行为,这是我必须提供的唯一其他Delphi版本.

在调试器下跟踪并发现自己在_GetMem中,Size参数等于264,因此显然没有分配足够的内存.

如果有任何疑问,这个版本失败了AV.

program InstanceSizeBug;

{$APPTYPE CONSOLE}

type
  TMyClass<T> = class
    V: array [1..256*256] of T;
  end;
  TMyClassSingle = class(TMyClass<Single>);

begin
  TMyClassSingle.Create.V[256*256] := 0;
end.@H_301_9@ 
 

我已将此提交给Quality Central,问题#100561.

作为一种解决方法,我建议您使用在构造函数中使用SetLength分配的动态数组.我宁愿想象它是一个固定大小的通用数组的存在,使编译器行为不端.

原文链接:https://www.f2er.com/delphi/102276.html

猜你在找的Delphi相关文章