4

假设我有以下带有以下声明的自定义列表:

type 
  TCustomList = class(TObjectList)
  private
    function GetItem(AIndex: Integer): TMyObject; // virtual;
    procedure SetItem(Index: Integer; AObject: TMyObject);
...
  public
    property Items[Index: Integer]: TMyObject read GetItem write SetItem;
    procedure InsertSort();
  end;

通过以下实现:

implementation

function TCustomList.GetItem(AIndex: Integer): TMyObject;
begin
  Result := TMyObject(inherited Items[AIndex]);
end;

procedure TCustomList.SetItem(Index: Integer; AObject: TMyObject);
begin
    inherited Items[Index]:= AObject;
end;

procedure TCustomList.InsertSort;
var
  i, j: integer;
  key: TMyObject;
begin
  for j := 1 to self.Count - 1 do
  begin
    key:= self.Items[j];
    i := j - 1;
    while ((i >= 0) AND (self.Items[i].Compare(key)>0)) do
    begin
        self.Items[i+1]:= self.Items[i]; // does not WORK!!! properly.. System.Contnrs problem ?? 
        i := i-1;
    end; // while
    self.Items[i+1]:= key;
  end; // for
end; // procedure InsertSort

当我在 的实例集合上运行代码时TMyObject,我得到一个无效指针操作异常。我认为,这是由于TCustomListviaItems属性的元素的读取和写入不佳造成的。

为什么会出现这个无效指针操作异常?

4

1 回答 1

6

这里发生的事情是对象列表的所有权正在阻碍。因为您正在使用TObjectList,所以无论何时要求列表忘记某个成员,它都会将其销毁。当您编写代码时,这会发生在您的代码中:

self.Items[i+1] := ...

在销毁分配之前存储在索引中的成员,i+1以便为新项目腾出空间。最终,您将最终销毁一个已经被销毁的对象,这就是您的无效指针异常发生的时候。

要解决此问题,可以使用Extract允许您删除项目而不破坏它的方法。或者正如@Arioch 在评论中巧妙地指出的那样,该Exchange方法非常适合比较排序。

更容易的是在排序期间临时切换OwnsObjectsFalse,不要忘记在完成后恢复它。或者,也许您甚至不想使用OwnsObjects=True. 在那种情况下,你想要TList

Frankly though you'd be far better off using the in-built Sort method that is originally exposed by TList. There's simply no need for you to implement a sort method on a class that already comes with a perfectly decent one.

于 2013-03-05T15:32:43.607 回答