2014-12-03 59 views
1

分配默認(TMyRecord)至TMyRecord的一個變量與所述內部調用第一完成並然後清零等FillChar存儲器會。這在回答以下問題,比如有人說,我也測試分配默認()確實會調用例如System._FinalizeRecord使用Default()賦值來初始化Delphi中的記錄變量是否安全?

How to properly free records that contain various types in Delphi at once?

Difference between Initialize(), Default() and FillChar()

我的問題是不是初始化這樣的記錄,即使在Delphi沒有自動調用Initialize的情況下也是如此?對我來說,在未初始化的記錄變量上調用Finalize似乎沒有任何意義。在初始化之前,必須假定內存包含隨機垃圾。在這種情況下,我特別感興趣的是託管類型,它們是指向動態分配內存的指針,Finalize例程應通過減少其引用計數來完成,等等。在很多情況下,Delphi會自動生成對Initialize的調用,以確保其託管類型保持託管狀態。但不總是。

這裏是示出有問題的情況下的例子。正如下面的答案評論說,你不應該使用的getmem分配包含託管類型這樣的記錄,但讓我們只是假設有人做,然後試圖用默認()分配爲初始化

type 
    TMyRecord = record 
    s1, s2, s3 : String; 
    end; 
    PMyRecord = ^TMyRecord; 

var 
    pr : PMyRecord; 

begin 
    GetMem(pr, SizeOf(TMyRecord)); 
    pr^ := Default(TMyRecord); 
... 

我故意使用的getmem ()而不是New(),因爲據我所知,GetMem()返回的內存不應該自動清零,編譯器也不應該自動調用Initialize。所以在這種情況下,使用默認分配初始化記錄不是不安全的嗎?

在大衛在這裏接受的答案,他正在使用的記錄類型一記漂亮的清除方法 How to properly free records that contain various types in Delphi at once? 讓我們添加一個

TMyRecord = record 
    s1, s2, s3 : String; 
    procedure Clear; 
    end; 
... 
procedure TMyRecord.Clear; 
begin 
    Self := Default(TMyRecord); 
end; 

現在,清除例程應該絕對沒有辦法知道,如果記錄坐在堆棧或堆上,並且Initialize已被調用,否則。

回答

3

所以在這種情況下,使用默認賦值來初始化記錄不是不安全嗎?

是的,這是不安全的。這將最終確定垃圾,這可能很容易崩潰,或更糟。

如果您需要初始化內存,使用Initialize方法,或寫一些東西,其中編譯器將隱做代表您。

現在,那個Clear例程應該完全無法知道記錄是否坐在堆棧或堆上,並且Initialize已被調用。

該代碼已假定Initialize已被調用,並已將該責任轉移給調用者。這對我來說非常有意義。必須處理未初始化內存的代碼是例外情況,而不是標準。

換句話說,該代碼不是爲了做你想做的事情而設計的。這不會使代碼有任何缺陷。它擅長什麼它設計的。

7
GetMem(pr, SizeOf(TMyRecord)); 
pr^ := Default(TMyRecord); 

上述代碼不正確。但是這與使用Default()無關。考慮以下代碼:

GetMem(pr, SizeOf(TMyRecord)); 
pr^ := ...; 

此代碼是不正確不管你用替換...。換句話說,你的代碼的問題不是使用Default()。問題是使用GetMem。在調用GetMem之後,新分配的內存的內容不明確。分配完成後,第一步是確定記錄的當前內容。由於這些內容不明確,任何事情都可能發生。

當動態分配包含託管類型的記錄時,預計使用New。如果您在這種情況下只需使用GetMem,則需要負責確保記錄中的託管成員在任何後續使用記錄之前進行適當的初始化。

所以我認爲你給你的問題錯了標題。而不是

是否可以安全使用Default()賦值來初始化記錄?

的問題應該已經題爲

是否安全已經初始化之前做任何記錄?

+2

只是添加,有人可能會說,「怎麼樣AllocMem零分配內存」?但是,使用'GetMem'和'AllocMem'你可以使用'FreeMem',它不能最終確定,而使用'New'你可以使用'Dispose'來確定。 – 2014-12-03 15:57:49

+0

感謝您的深刻評論,但我真的很想具體詢問如何使用Default()賦值來初始化記錄。對我來說,這似乎是一個不好的主意,因爲對我來說,在某些情況下,它似乎有效地調用Finalize處理未初始化的垃圾。 – 2014-12-03 16:30:59

+0

我想你在這種情況下根本不理解我的答案。我無法想出任何更好的表達方式。你對我的回答的評論清楚表明你對這些問題的理解是錯誤的。我不能強迫你改正這一點。 – 2014-12-03 16:33:08

相關問題