2014-03-13 24 views
8

在32位和64位下編譯時,TPair的默認排序似乎有區別。在32位以下,默認的排序就像它在64位的對中的鍵排序一樣,它看起來是按值排序的。這是預期的,還是我錯過了什麼?使用默認排序對一個TList <TPair <整數,整數>>進行排序

測試用Delphi XE2,更新4.在一個VCL應用,下降按鈕,複選框,列表框到屏幕上,聲明下述類型

type TPairComparer = TComparer<TPair<integer,integer>>; 

然後將下面的代碼在按鈕的OnClick和運行。在32位下,使用默認排序,這些對通過鍵列出,即1,2,3,4,5,6。在64位下,這些對按值列出,即2,5,6,7,8,9而不是按鍵。

爲了讓代碼在兩個平臺上一致地工作,我需要指定我自己的比較器來強制按64位可執行文件上的鍵排序。

procedure TForm1.Button1Click(Sender: TObject); 
var PriorityList   : TList<TPair<Integer,integer>>; 
    Pair     : TPair<integer,integer>; 
    PairComparer   : IComparer<TPair<integer,integer>>; 
    iLoop     : integer; 
begin 

PriorityList := TList<TPair<Integer,integer>>.Create; 

PairComparer := TPairComparer.Construct(
function(const Left, Right: TPair<integer,integer>): Integer 
begin 
     case Left.Key = Right.Key of 
      true : Result := 0; 
     else  case Left.Key < Right.Key of 
         true : Result := -1; 
        else  Result := +1; 
        end; 
     end; 
end); 

Pair.Key := 6; 
Pair.Value := 6; 
PriorityList.Add(Pair); 

Pair.Key := 5; 
Pair.Value := 5; 
PriorityList.Add(Pair); 

Pair.Key := 4; 
Pair.Value := 8; 
PriorityList.Add(Pair); 

Pair.Key := 3; 
Pair.Value := 9; 
PriorityList.Add(Pair); 

Pair.Key := 2; 
Pair.Value := 7; 
PriorityList.Add(Pair); 

Pair.Key := 1; 
Pair.Value := 2; 
PriorityList.Add(Pair); 

case Checkbox1.Checked of 
     true : PriorityList.Sort; 
     false : PriorityList.Sort(PairComparer); 
end; 

ListBox1.Clear; 
for iLoop := 0 to PriorityList.Count-1 do 
    ListBox1.Items.Add(Format('Key : %d , Value : %d',[PriorityList[iLoop].Key,PriorityList[iLoop].Value])); 

end;

+2

請不要寫'case of'。只需使用簡單的'if'語句即可。它的方式更具可讀性。 –

+0

每一個給他自己。 – Paul

回答

6

這種類型的默認比較器是非常隨意的。編譯器不使用關於組成記錄的任何知識。你當然沒有告訴它你想成爲主要排序鍵的成員。所以它可以自由地做它想做的事情。

在32位中,8字節記錄的默認比較器通過調用類似CompareMem的函數來實現。所以字節按地址的升序進行比較。因此關鍵更重要。

在64位下,默認比較器將該類型視爲無符號的64位整數,因此字節按遞減的地址順序進行比較,這是小尾​​數。所以價值更重要。

相關的代碼是在Generics.Defaults實現部分:

function Comparer_Selector_Binary(info: PTypeInfo; size: Integer): Pointer; 
begin 
    case size of 
    // NOTE: Little-endianness may cause counterintuitive results, 
    // but the results will at least be consistent. 
    1: Result := @Comparer_Instance_U1; 
    2: Result := @Comparer_Instance_U2; 
    4: Result := @Comparer_Instance_U4; 
    {$IFDEF CPUX64} 
    // 64-bit will pass const args in registers 
    8: Result := @Comparer_Instance_U8; 
    {$ENDIF} 
    else 
    Result := MakeInstance(@Comparer_Vtable_Binary, size); 
    end; 
end; 

底線是,你需要提供一個真正的比較器,只要你想記錄進行排序。只有在數字和字符串類型中內置了定義明確的有序比較器。

+2

「只有以數字和字符串類型構建的定義良好的有序比較器纔有效。」如果你曾經看過TOrdinalStringComparer.Compare,你不會那麼說;) –

+0

謝謝大衛,現在有道理。這是我依賴於非重要數據的默認排序的唯一例子之一。獲得的教訓,始終指定一個比較器... – Paul

相關問題