Ren*_*ann 3 delphi rtti dynamic-arrays delphi-10.2-tokyo
我在Delphi 10.2 Update 2中遇到了与RTTI相关的问题,并且能够将其跟踪到更少的代码量(见下文).
我有一些TPersistent-descendant类TMyObj发布类型的属性TArray<Integer>.当我通过GetDynArrayProp()它接收它的值并通过它查询它的大小时,DynArraySize()只能达到649个元素的大小.在此特殊计数之上返回一些非常大的值.
请注意,我的数组是从一个实例生成TDictionary<Integer,Boolean>的Keys拥有自己的财产ToArray的方法.我也尝试修改,TMyObj.GetDynArray以便它TArray<Integer>直接返回一个实例,它正常工作.因此,我认为这可能会以一些神秘的方式相关联.
我的使用有DynArraySize()什么问题?这种动态数组的神秘行为背后是什么?
program RTTIPropDynArray;
{$APPTYPE CONSOLE}
uses
System.Classes, System.Generics.Collections, System.SysUtils, System.TypInfo;
type
TMyDict = TDictionary<Integer,Boolean>;
TMyArray = TArray<Integer>;
TMyObj = class(TPersistent)
private
FValues: TMyDict;
function GetDynArray: TMyArray;
public
constructor Create(const ACount: Integer);
destructor Destroy; override;
published
property DynArray: TMyArray read GetDynArray;
end;
{ TMyObj }
constructor TMyObj.Create(const ACount: Integer);
begin
FValues := TMyDict.Create;
while FValues.Count < ACount do
FValues.AddOrSetValue(Random(MaxInt), False);
end;
destructor TMyObj.Destroy;
begin
FreeAndNil(FValues);
inherited;
end;
function TMyObj.GetDynArray: TMyArray;
begin
Result := FValues.Keys.ToArray;
end;
function Test(const ACount: Integer): Boolean;
var
LInstance: TMyObj;
LExpectedSize: Integer;
LDynArraySize: Integer;
begin
LInstance := TMyObj.Create(ACount);
try
LExpectedSize := Length(LInstance.DynArray);
LDynArraySize := DynArraySize(GetDynArrayProp(LInstance, 'DynArray'));
Result := LExpectedSize = LDynArraySize;
if not Result then
WriteLn(Format('Expected size: %d; DynArraySize: %d', [LExpectedSize, LDynArraySize]));
finally
LInstance.Free;
end;
end;
var
LCount: Integer;
begin
Randomize;
LCount := 1;
while Test(LCount) do
Inc(LCount);
ReadLn;
end.
Run Code Online (Sandbox Code Playgroud)
简短的回答:你的代码坏了
答案很长:
吸气剂的呼叫创建一个新的阵列(见TEnumerable<T>.ToArrayImpl中System.Generics.Collections.pas),这是在的结尾被释放System.TypInfo.GetDynArrayProp(放一个断点,并期待入拆装-它显示@DynArrayClear).由于没有对此数组的其他引用,因此其内存将被释放(如果您System.pas进一步深入,您将看到它最终会被终止_FreeMem).这意味着每次调用此函数都会返回一个悬空指针!
现在为什么在之前的所有电话中都能得到正确的结果?巧合 - 记忆尚未被其他任何东西重新分配.
我想到两个可能的解决方案,不涉及重写getter:
System.Rtti.pas为TValue保持基准活着GetDynArrayProp,保持基准活着-但你必须确保随时调用DynArrayClear后或创建内存泄漏我个人会使用第一个.
| 归档时间: |
|
| 查看次数: |
138 次 |
| 最近记录: |