Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 德尔福TQUUE车吗?使用TQUUE<;t字节>;返回nil并退出队列_Delphi_Delphi 10.2 Tokyo - Fatal编程技术网

Delphi 德尔福TQUUE车吗?使用TQUUE<;t字节>;返回nil并退出队列

Delphi 德尔福TQUUE车吗?使用TQUUE<;t字节>;返回nil并退出队列,delphi,delphi-10.2-tokyo,Delphi,Delphi 10.2 Tokyo,我不明白为什么这个非常简单的代码失败了?我在Delphi东京版2上 {$APPTYPE CONSOLE} uses System.SysUtils, System.Generics.Collections; procedure Main; var aQueue: TQueue<TBytes>; aBytes: TBytes; begin aQueue := TQueue<TBytes>.create; aBytes := TEncoding.

我不明白为什么这个非常简单的代码失败了?我在Delphi东京版2上

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Generics.Collections;

procedure Main;
var
  aQueue: TQueue<TBytes>;
  aBytes: TBytes;
begin
  aQueue := TQueue<TBytes>.create;

  aBytes := TEncoding.UTF8.GetBytes('abcd');
  aQueue.Enqueue(aBytes);
  aBytes := aQueue.Dequeue;
  Writeln(Length(aBytes)); // outputs 4 as expected

  aBytes := TEncoding.UTF8.GetBytes('abcd');
  aQueue.Enqueue(aBytes);
  aBytes := aQueue.Dequeue;
  Writeln(Length(aBytes)); // outputs 0
end;

begin
  Main;
  Readln;
end.
{$APPTYPE控制台}
使用
System.SysUtils,
系统、泛型、集合;
主程序;
变量
问题:问题;
aBytes:TBytes;
开始
aQueue:=TQueue.create;
aBytes:=TEncoding.UTF8.GetBytes('abcd');
队列(aBytes);
aBytes:=aQueue.Dequeue;
Writeln(长度(字节));//产出4如预期
aBytes:=TEncoding.UTF8.GetBytes('abcd');
队列(aBytes);
aBytes:=aQueue.Dequeue;
Writeln(长度(字节));//产出0
结束;
开始
主要的;
Readln;
结束。
这是虫子吗


注意:该代码在XE4上正常工作,但在Berlin上也失败。

这确实是一个bug。代码可以在XE7中正常工作,但不能在XE8中正常工作。在XE8中,两次尝试的输出均为
0

当然,XE8泛型集合有很多缺陷,后续版本修复了许多缺陷。显然,并非所有问题都得到了解决

在XE8中,Embarcadero试图解决编译/链接模型中的缺陷导致的通用膨胀问题。不幸的是,他们没有从根本上解决这个问题,而是选择在泛型集合的库代码中解决这个问题。这样做,他们完全打破了许多泛型集合类,证明了他们的单元测试很弱。当然,通过这种方式解决问题,他们没有解决泛型集合以外的类的泛型膨胀问题。总而言之,一个似乎还没有结束的遗憾故事

已提交错误报告:

请注意,此错误报告不正确,因为(至少根据Stefan Glienke的说法)该错误已在东京10.2.3中修复。因此,升级到10.2.3应该是解决问题的最简单方法

也许这个bug报告更合适:

编写通用队列甚至并不困难。这里有一个已知的有效方法:

type
  TQueue<T> = class
  private
    FItems: TArray<T>;
    FCount: Integer;
    FFront: Integer;
  private
    function Extract(Index: Integer): T; inline;
    function GetBack: Integer; inline;
    property Back: Integer read GetBack;
    property Front: Integer read FFront;
    procedure Grow;
    procedure RetreatFront; inline;
  public
    property Count: Integer read FCount;
    procedure Clear;
    procedure Enqueue(const Value: T);
    function Dequeue: T;
    function Peek: T;
  public
    type
      TEnumerator = record
      private
        FCollection: TQueue<T>;
        FCount: Integer;
        FCapacity: Integer;
        FIndex: Integer;
        FStartIndex: Integer;
      public
        class function New(Collection: TQueue<T>): TEnumerator; static;
        function GetCurrent: T;
        property Current: T read GetCurrent;
        function MoveNext: Boolean;
      end;
  public
    function GetEnumerator: TEnumerator;
  end;

function GrownCapacity(OldCapacity: Integer): Integer;
var
  Delta: Integer;
begin
  if OldCapacity>64 then begin
    Delta := OldCapacity div 4
  end else if OldCapacity>8 then begin
    Delta := 16
  end else begin
    Delta := 4;
  end;
  Result := OldCapacity + Delta;
end;

{ TQueue<T> }

function TQueue<T>.Extract(Index: Integer): T;
begin
  Result := FItems[Index];
  if IsManagedType(T) then begin
    Finalize(FItems[Index]);
  end;
end;

function TQueue<T>.GetBack: Integer;
begin
  Result := Front + Count - 1;
  if Result>high(FItems) then begin
    dec(Result, Length(FItems));
  end;
end;

procedure TQueue<T>.Grow;
var
  Index: Integer;
  Value: T;
  Capacity: Integer;
  NewItems: TArray<T>;
begin
  Capacity := Length(FItems);
  if Count=Capacity then begin
    SetLength(NewItems, GrownCapacity(Capacity));
    Index := 0;
    for Value in Self do begin
      NewItems[Index] := Value;
      inc(Index);
    end;

    FItems := NewItems;
    FFront := 0;
  end;
end;

procedure TQueue<T>.RetreatFront;
begin
  inc(FFront);
  if FFront=Length(FItems) then begin
    FFront := 0;
  end;
end;

procedure TQueue<T>.Clear;
begin
  FItems := nil;
  FCount := 0;
end;

procedure TQueue<T>.Enqueue(const Value: T);
begin
  Grow;
  inc(FCount);
  FItems[Back] := Value;
end;

function TQueue<T>.Dequeue: T;
var
  Index: Integer;
begin
  Assert(Count>0);
  Result := Extract(Front);
  RetreatFront;
  dec(FCount);
end;

function TQueue<T>.Peek: T;
begin
  Assert(Count>0);
  Result := FItems[Front];
end;

function TQueue<T>.GetEnumerator: TEnumerator;
begin
  Result := TEnumerator.New(Self);
end;

{ TQueue<T>.TEnumerator }

class function TQueue<T>.TEnumerator.New(Collection: TQueue<T>): TEnumerator;
begin
  Result.FCollection := Collection;
  Result.FCount := Collection.Count;
  Result.FCapacity := Length(Collection.FItems);
  Result.FIndex := -1;
  Result.FStartIndex := Collection.Front;
end;

function TQueue<T>.TEnumerator.GetCurrent: T;
var
  ActualIndex: Integer;
begin
  ActualIndex := (FStartIndex + FIndex) mod FCapacity;
  Result := FCollection.FItems[ActualIndex];
end;

function TQueue<T>.TEnumerator.MoveNext: Boolean;
begin
  inc(FIndex);
  Result := FIndex<FCount;
end;
类型
类
私有的
FItems:TArray;
FCount:整数;
fffront:整数;
私有的
函数提取(索引:整数):T;内联;
函数GetBack:Integer;内联;
属性返回:整数读取返回;
属性前端:整数读取前端;
程序生长;
程序前沿;内联;
公众的
属性计数:整数读取FCount;
程序清晰;
程序排队(常数值:T);
函数出列:T;
功能Peek:T;
公众的
类型
纤毛器=记录
私有的
F收集:TQueue;
FCount:整数;
FCapacity:整数;
FIndex:整数;
FStartIndex:整数;
公众的
类函数New(集合:TQueue):TEnumerator;静止的
函数GetCurrent:T;
属性当前:T读取GetCurrent;
函数MoveNext:布尔;
结束;
公众的
函数GetEnumerator:TEnumerator;
结束;
函数增长容量(旧容量:整数):整数;
变量
Delta:整数;
开始
如果OldCapacity>64,则开始
增量:=旧容量分区4
如果OldCapacity>8,则结束else,然后开始
增量:=16
结束,否则开始
δ=4;
结束;
结果:=旧容量+增量;
结束;
{TQueue}
函数TQueue.Extract(索引:整数):T;
开始
结果:=FItems[指数];
如果是IsManagedType(T),则开始
最终确定(FItems[索引]);
结束;
结束;
函数TQueue.GetBack:整数;
开始
结果:=前端+计数-1;
如果结果>高(FItems),则开始
dec(结果、长度(FItems));
结束;
结束;
程序TQUUE.成长;
变量
索引:整数;
值:T;
容量:整数;
新项目:柏油虫;
开始
容量:=长度(FItems);
如果计数=容量,则开始
设置长度(新项目、增长容量(容量));
指数:=0;
为了自我价值,开始吧
NewItems[索引]:=值;
公司(指数),;
结束;
FItems:=新项目;
FFront:=0;
结束;
结束;
程序TQUUE.REVERTIONE;
开始
公司(前线),;
如果FFront=长度(FItems),则开始
FFront:=0;
结束;
结束;
程序清晰;
开始
FItems:=零;
f计数:=0;
结束;
程序TQueue.Enqueue(常量值:T);
开始
成长;
公司(FCount);
FItems[Back]:=值;
结束;
函数TQueue.Dequeue:T;
变量
索引:整数;
开始
断言(计数>0);
结果:=提取(前);
撤退前线;
dec(FCount);
结束;
函数TQueue.Peek:T;
开始
断言(计数>0);
结果:=FItems[前];
结束;
函数TQUUE.GetEnumerator:TEnumerator;
开始
结果:=TEnumerator.New(Self);
结束;
{TQueue.TEnumerator}
类函数TQueue.TEnumerator.New(集合:TQueue):TEnumerator;
开始
Result.FCollection:=集合;
Result.FCount:=集合.计数;
Result.FCapacity:=长度(Collection.FItems);
Result.FIndex:=-1;
Result.FStartIndex:=Collection.Front;
结束;
函数TQueue.TEnumerator.GetCurrent:T;
变量
实际指数:整数;
开始
实际指数:=(FStartIndex+FIndex)mod FCapacity;
结果:=FCollection.FItems[ActualIndex];
结束;
函数TQueue.TEnumerator.MoveNext:布尔值;
开始
公司(FIndex),;

结果:=FIndex要添加到David的答案中,错误出现在
Enqueue
方法中。顶部分支应处理所有引用计数的托管类型

  if IsManagedType(T) then
    if (SizeOf(T) = SizeOf(Pointer)) and (GetTypeKind(T) <> tkRecord) then
      FQueueHelper.InternalEnqueueMRef(Value, GetTypeKind(T))
    else
      FQueueHelper.InternalEnqueueManaged(Value)
  else
事实上,这太离谱了,编译器在编译时实际上没有为
排队
生成任何代码(除了序言),因为可以从编译时的类型来确定练习的无效性

Project1.dpr.15: aQueue.Enqueue(aBytes);
0043E19E 8B45F8           mov eax,[ebp-$08]
0043E1A1 8945F4           mov [ebp-$0c],eax
0043E1A4 8B45FC           mov eax,[ebp-$04]
0043E1A7 83C008           add eax,$08
0043E1AA 8945F0           mov [ebp-$10],eax
Project1.dpr.16: aBytes := aQueue.Dequeue;
0043E1AD 8D45EC           lea eax,[ebp-$14]

因此,对于任何类型的动态数组,
T
,这个bug都会影响
TQueue

投-1票的家伙,他能在评论中分享为什么投-1票吗?其他人也一样,他们也会这么做……不,不,这是完全相同的代码(在一个空白的新项目上复制过去)!没有别的了。。。我在德尔福东京发布2@DavidHeffernan:在《东京版》上,你是?Yikes。我已经习惯了“标准库是否有故障”的问题通常是以
Project1.dpr.15: aQueue.Enqueue(aBytes);
0043E19E 8B45F8           mov eax,[ebp-$08]
0043E1A1 8945F4           mov [ebp-$0c],eax
0043E1A4 8B45FC           mov eax,[ebp-$04]
0043E1A7 83C008           add eax,$08
0043E1AA 8945F0           mov [ebp-$10],eax
Project1.dpr.16: aBytes := aQueue.Dequeue;
0043E1AD 8D45EC           lea eax,[ebp-$14]