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、invalid-pointer-operation例外が発生します。TCustomListこれは、 viaItemsプロパティの要素の読み取りと書き込みが不十分なことが原因であると私は信じています。

このinvalid-pointer-operation例外が表示されるのはなぜですか?

4

1 に答える 1

6

ここで起こっているのは、オブジェクト リストの所有権が邪魔をしていることです。を使用しているためTObjectList、リストがメンバーを削除するように求められると、リストは破棄されます。これは、次のように記述したときにコード内で発生します。

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

割り当て前に index に格納されているメンバーはi+1、新しいアイテム用のスペースを作るために破棄されます。最終的には、すでに破棄されているオブジェクトを破棄することになり、そのときに無効なポインター例外が発生します。

この問題を解決するにはExtract、アイテムを破壊せずに削除できる方法を利用できます。または、@Arioch がコメントでスマートに指摘しているように、Exchange比較ソートに最適な方法です。

さらに簡単なのは、並べ替え中に一時的に切り替えるOwnsObjectsことFalseであり、完了したら元に戻すことを忘れないでください。または、使用するつもりさえなかったのかもしれませんOwnsObjects=True。その場合、TList代わりに必要です。

率直に言って、Sort元々TList. 完全にまともなクラスがすでに付属しているクラスに、並べ替えメソッドを実装する必要はまったくありません。

于 2013-03-05T15:32:43.607 に答える