2013-03-05 32 views
4

讓我們假設我有以下聲明如下自定義列表:當我重新排列TObjectList時,爲什麼會出現「無效指針操作」?

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實例的集合運行的代碼,我得到一個無效的指針操作異常。我相信這是由於的元素通過Items屬性讀取和寫入不佳而造成的。

爲什麼這個無效指針操作異常出現?

回答

6

這裏發生的事情是,對象列表的所有權正在受到阻礙。因爲您使用的是TObjectList,所以只要該列表被要求忘記某個成員,就會將其摧毀。這發生在你的代碼,當你寫:

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

被分配被破壞以騰出空間給新的項目之前存儲在索引i+1成員。最終,你最終會銷燬一個已經被銷燬的對象,這就是你的無效指針異常發生的時候。

要解決該問題可以使用Extract方法,它允許您刪除一個項目而不會破壞它。或者@Arioch在評論中巧妙地指出,Exchange方法非常適合比較排序。

更簡單的方法是在排序過程中暫時將OwnsObjects切換爲False,而不要忘記在完成時將其恢復。或者,您甚至可能沒有使用OwnsObjects=True。在這種情況下,您需要改爲TList

坦率地說,儘管使用最初由TList公開的內置Sort方法會更好。你根本沒有必要在已經有完美體面的課程上實施排序方法。

+0

謝謝!我也認爲TObjectList正是這樣做的,即試圖摧毀同一個對象兩次。我會嘗試你的解決方案,併發布,如果它的工作。 – kenny 2013-03-05 15:44:34

+1

一個解決方案,如你所建議的:使用內置的TList.Sort函數,如下所示: 調用'myCustomList.Sort(@ MyObject.Compare)' - 帶有@ MyObject.Compare是一個指向TMyObject內部實現的比較函數的指針。 我試過的第二種方法是: invoke 'self.OwnsObjects:= false;'在TCustomList.InsertSort的for循環之前的 ;然後'self.OwnsObjects:= true;'排序完成後,排序爲 。 謝謝,大衛,我會掙扎很多。 – kenny 2013-03-05 16:05:13

+0

您需要將比較函數實現爲獨立函數而不是實例方法。你的代碼調用'Sort'可能有效,但這有點意外。一個建議的話。不要使用@來獲取函數指針。 – 2013-03-05 16:12:48

相關問題