2015-06-28 51 views
-1

我需要一個數組,它在運行時對一次性初始化進行了優化,並具有給定的長度。所以內存應該在運行時分配,但我不需要改變它的長度。如何在delphi中聲明一個可變長度的靜態數組?

是否存在除純動態數組之外的數組類型? (這似乎是無法完成這個任務的最佳選擇)

獎金會是這樣,如果初始化數組是通過指針迭代可轉位,所以它的所有元素被分配在內存中連續的。

這是一個非經驗的程序員的一切只是一個白日夢,或者是有可能實現這一目標?

我能想象與手動內存分配要做到這一點,但也許有另一種方式。

編輯:

我主要關注的是陣列的讀寫速度。

+0

不,沒有。它不再是靜態的。 – TLama

+1

那麼究竟是什麼阻止我在運行時初始化靜態數組?在編譯的硬編碼內存塊和運行時生成的「保證內存塊」數組之間有什麼不同? – Art1st

+1

@ Art1st如果初始化(包括分配)發生在您自己的代碼中,那必然意味着在可以運行的初始化之前可能存在代碼*。 (例如,如果您有兩個這樣的數組,則一個初始化必須在另一個之前執行。)如果其他代碼訪問尚未初始化的數組,則會發生什麼情況?無論你的答案是什麼,這是否意味着數組更像靜態數組,或更像是一個動態數組? (我強烈懷疑後者。) – hvd

回答

2

你可以在通用類型中封裝你想要的東西。就像這樣:

type 
    TFixedLengthArray<T> = record 
    strict private 
    FItems: TArray<T>; 
    FLength: Integer; 
    function GetItem(Index: Integer): T; inline; 
    procedure SetItem(Index: Integer; const Value: T); inline; 
    public 
    property Length: Integer read FLength; 
    property Items[Index: Integer]: T read GetItem write SetItem; default; 
    class function New(const Values: array of T): TFixedLengthArray<T>; static; 
    end; 

{ TFixedLengthArray<T> } 

class function TFixedLengthArray<T>.New(const Values: array of T): TFixedLengthArray<T>; 
var 
    i: Integer; 
begin 
    Result.FLength := System.Length(Values); 
    SetLength(Result.FItems, Result.FLength); 
    for i := 0 to Result.FLength-1 do begin 
    Result.FItems[i] := Values[i]; 
    end; 
end; 

function TFixedLengthArray<T>.GetItem(Index: Integer): T; 
begin 
    Result := FItems[Index]; 
end; 

procedure TFixedLengthArray<T>.SetItem(Index: Integer; const Value: T); 
begin 
    FItems[Index] := Value; 
end; 

創建一個新的一個是這樣的:

var 
    MyArray: TFixedLengthArray<Integer>; 
.... 
MyArray: TFixedLengthArray<Integer>.New([1, 42, 666]); 

Access項目中是這樣的:

for i := 0 to MyArray.Length-1 do 
    Writeln(MyArray[i]); 

這只是包裝一個動態數組。元素是連續的。數組的長度決定一勞永逸,然後創建一個新的實例。

有一點要注意這裏是該類型將像一個引用類型,因爲它的數據存儲在引用類型。也就是說,這種類型的賦值運算符的行爲方式與動態數組賦值相同。

因此,如果我們有這種類型的兩個變量,arr1arr2然後會發生以下情況:

arr1 := arr2; 
arr1[0] := 42; 
Assert(arr2[0] = 42); 

如果你想使型表現得像一個真正的價值,那麼你會實現寫入時複製裏面有SetItem

更新

你編輯的問題變化顯著的。事實上,你似乎更關心性能而不是封裝。

在上述類型的項的存取方法的內聯意味着性能特性應接近陣列。訪問仍然是O(1),但內聯/優化器很弱並且無法發出最優代碼是非常合理的。

在你決定,你必須使用數組,以獲得絕對極致的表現,做一些真實世界的標杆。在我看來,從陣列讀取/寫入的代碼確實是一個瓶頸的可能性非常小。最有可能的瓶頸將是你對數組中的值做什麼。

+0

與僅使用TArray 相比,是否有這種速度優勢,或者這只是爲了防止程序員在運行時改變其長度? – Art1st

+0

不可能是速度差異。如果內襯擰緊,它會變慢。閱讀時間可能會更快,但我懷疑它。重點是停止編程改變長度,這正是我所理解的你所要求的。 –

+0

我這個問題的主要原因確實是速度問題,我希望有一種確保緊湊內存的類型,所以我可以正好訪問O(1)中的任何數組項,但無論如何,這個答案給出了我的解決方案第二個問題,初始化後改變長度。 – Art1st

3

只需使用外部變量Count: integer,並使用動態數組長度作爲數組的「容量」。如果數組的初始容量定義良好,它將避免大部分內存分配。

實際上,單元中定義的TList<T>正在使用此方案:它在內部存儲一個數組,但它有自己的Count屬性。我懷疑這是你在找什麼。

對於更低級的東西,具有更多功能(如JSON或二進制序列化,或通過一個或多個屬性的散列進行快速查找),您可以查看我們的TDynArray dynamic array wrapper。這些只是現有動態數組的封裝,而不是像TList<T>這樣的數據保存器。他們從德爾福5或更老的工作,也是FPC。

相關問題