2010-08-11 45 views
8

我有很多內存分配和相同數量的FreeMem調用。我之前沒有的是在調用freemem之前查看指針是否爲零,並且釋放一行以將指針設置爲nil之後進行檢查。使用單個函數的Delphi中的空閒內存和零

我試圖創建一個函數來做到這一點

procedure FreeMemAndNil(p: Pointer; size: Integer = -1); 
begin 
    if p <> nil then 
    begin 
    if size > -1 then 
     FreeMem(p, size) 
    else 
     FreeMem(p); 
    p := nil; 
    end; 
end; 

但是有一個問題。它不能將原始指針設置爲nil,因爲該參數不是可變的(var p:Pointer)。我不能使用var,因爲如果我做的編譯器抱怨類型必須是完全相同的類型(指針)。我傳遞的指針可能是指向任何類型的指針(PChar,常規指針等)。

我能做些什麼來解決這個問題?有更好的解決方案嗎?

+0

有'FreeAndNil' http://www.delphibasics.co.uk/RTL.asp?Name=FreeAndNil – Andrey 2010-08-11 17:29:56

+0

@Andrey FreeAndNil只適用於對象。我正在處理手動分配給指針的內存。謝謝你的意見。 – Daisetsu 2010-08-11 17:35:37

回答

6

Mason Wheeler說你應該使用FreeAndNil相同的技巧在SysUtils單位做對象引用。
所以我修改你的代碼,單位進行了測試,並能正常工作:

procedure FreeMemAndNil(var ptr; size: Integer = -1); 
var 
    p: Pointer; 
begin 
    p := Pointer(ptr); 
    if p <> nil then 
    begin 
    if size > -1 then 
     FreeMem(p, size) 
    else 
     FreeMem(p); 
    Pointer(ptr) := nil; 
    end; 
end; 

--jeroen

PS:羅伯·肯尼迪寫了一個很好的答案上untyped var parameters,有一個鏈接到自己的非類型參數頁在網上。

PS2:僅供參考:The Kylix version of SysUtils.pas is on-line,FreeAndNil與Delphi中的相同。

+1

當然,如果您使用GPL下的Kylix代碼,並且沒有Kylix許可證,現在您的整個應用程序都是GPL。 – 2010-08-11 20:56:37

+1

上面顯示的代碼是* not *'FreeAndNil'。但是我不會使用這個代碼;我寧願使用Rob Kennedy的代碼。 – 2010-08-11 21:12:14

+0

@Andreas:它確實不是;來自Rob Kennedy的消息來源沒有Daisetu所要求的「size」參數,並且使用略微不同的排序和釋放順序。 – 2010-08-12 06:04:37

9

在SysUtils中有一個名爲FreeAndNil的過程可以爲對象執行此操作。它通過使用一個非類型化的參數將其轉換爲TObject來完成,並且由您來確保您不會傳遞不是TObject的東西。如果需要,你可以在這裏做類似的事情。請小心;如果你這樣做,沒有類型安全。

+0

感謝您的快速回復,我希望有一種方法可以說多個答案是正確的。 – Daisetsu 2010-08-11 20:35:50

+0

不,您必須僅選擇一個,但您可以在有限時間範圍內進行更改。 – 2010-08-11 20:45:01

13

爲了能夠將任意指針值傳遞給該函數,需要遵循與FreeAndNil相同的模型並傳入無類型參數。否則,編譯器會正確地抱怨實際和正式參數類型不相同。當您調用FreeMem時,請將untyped參數類型轉換爲指針。

你在這個功能上做了幾件毫無意義的事情。

首先是釋放一個零指針總是安全的,所以在調用FreeMem之前沒有理由去檢查它。它釋放了一個你需要擔心的非零指針,但沒有函數可以保護你。

接下來,FreeMem的size參數已被忽略多年。它曾經是,如果你提供了這個參數,它需要匹配傳遞給GetMem的大小,但是現在FreeMem完全忽略了這個參數 - 編譯器甚至不會將該參數傳遞給函數。

與所有在考慮到上述的,你的功能歸結爲:

procedure FreeMemAndNil(var P); 
var 
    Tmp: Pointer; 
begin 
    Tmp := Pointer(P); 
    Pointer(P) := nil; 
    FreeMem(Tmp); 
end; 

要小心,不要意外呼籲任何功能使用GetMem函數分配的指針。如果您使用的是鍵入的參數,編譯器無法爲您捕獲它。如果您嘗試釋放未使用GetMem分配的內容,您可能會收到EInvalidPointer異常,但您傳入的變量仍然爲零。這與FreeAndNil的工作方式相同。

+0

我仍然使用Delphi 6,它有一個很老的編譯器。如果我釋放了一個零指針,我得到一個錯誤,所以我確實需要首先檢查。你確定我不需要FreeMem的第二個參數,即使我使用了一個非常老的編譯器嗎? – Daisetsu 2010-08-11 18:56:26

+1

您錯誤診斷了問題。釋放一個零指針一直是安全的。你的問題在別處。 – 2010-08-11 19:31:15

+0

@Daisetsu - 我剛剛在D6上試過這個,它可以正常工作,沒有ptr。 'P:=零; FreeMem(P);'不給出錯誤。一個未分配的指針可能指向垃圾。 – 2010-08-11 20:48:07

4

我傾向於使用ReallocMem很多指針/內存操作。

調用

ReallocMem(P,0) 

將指針設置爲無。

1件事你需要知道使用它,P需要被傳遞給ReallocMem之前被初始化。

+0

+1;現在這對我來說是新的(似乎25年的Turbo Pascal經驗留下了足夠的空間來學習舊東西)。 – 2010-08-12 18:16:11

+0

是的,很酷的主意,錯誤地使用RealllocMem去分配。 – TheBlastOne 2011-04-07 16:00:52

相關問題