2016-03-02 24 views
4

我使用Delphi西雅圖。德爾福西雅圖:我釋放我創建的對象時得到無效指針操作

當我嘗試釋放我創建的對象時發生問題。

我在本網站(以及其他網站)搜索了已發佈的問題答案,但它們都有所不同。根據這些討論,我的代碼應該可以工作,但顯然有些事情是不正確的。

所以,我需要幫助...

流執行的:

一)在形式上fmLoanRequest,我創建基於類TStorageLoan(對象的子類TLoan的)。構造函數將所有類型的值加載到對象的某些屬性中(現在在此處顯示)。

b)稍後,我將該對象的地址傳遞給另一個窗體(fmLoan)以適當的公共變量。 fmLoan是所有用戶與貸款內容發生交易的形式。請注意,fmLoanRequest在我們處於fmLoan狀態時保持不變。當fmLoan關閉時,我們將返回fmLoanrequest。

c)顯示fmLoan表單(並顯示對象中的數據 - 所有工作正常)。

d)當關閉fmLoan,一個過程被調用以釋放貸款對象 - 如果它被分配(見行10秒的代碼片段)。這似乎工作正常(沒有錯誤)。 e)當執行下面第14行中的代碼時,出現'無效指針操作'錯誤:(如果分配(oLoan)然後oLoan.Free;)。

我已經添加了這一行,以確保如果fmLoan沒有出於某種原因處理它,該對象將被釋放。我意識到這個對象已經被釋放了,但是不應該'如果Assgned()'阻止了對象的不必要的釋放?

偏碼從形式fmLoanRequest(I加入一些供參考的行號)

1 // In form fmLoanRequest 
2 // Create new Loan Object (from a Loan sub-class as it happens) 
3 // Create the object here; Object address will be passed to fmLoan later for handling. 
4 oLoan := TStorageLoan.Create(iNewLoanID); 
5 ... 
6 ... 
7  fmLoan.oLoan := oLoan; // pass the address to the other form 
8  fmLoan.show; 
9  // User would click the 'btnClose' at this point. See event code below. 
10 ... 
11 ... 
12 procedure TfmLoanRequests.btnCloseClick(Sender: TObject); 
13 begin 
14  if Assigned(oLoan) then oLoan.Free; // <--- ERROR HERE 
15  fmLoanRequests.Close; 
16 end; 

偏碼從形式fmLoan(I加入一些供參考的行號)

1 //Form fmLoan 
2 ... 
3 public 
4  oLoan : TLoan; 
5 ... 
6 // In form fmLoan, I call the following upon closing the Form 
7 //     in the OnClick event of the 'btnClose' button. 
8 Procedure TfmLoan.Clear_Loan_Object; 
9 begin 
10 if Assigned(oLoan) then oLoan.Free; // <-- THIS WORKS FINE 
11 end; 

我應該嘗試一種不同的方法嗎?

我應該只刪除該行(第14行 - 第一個代碼片段),並希望最好。這不符合我的正確編碼理念!

我會以錯誤的方式去做嗎?

注:我顯然不使用指針。

任何幫助,將不勝感激!

+0

[爲什麼我在使用或釋放​​事物之前不應該使用「if Assigned()」?](http://stackoverflow.com/q/8548843/327083) –

+0

您可以在所有地方始終使用FreeAndNil(oLoan)你在哪裏使用oLoan.free。通過這種方式,您對Assigned(oLoan)的測試將在您期望時返回true。 – nolaspeaker

回答

2

很明顯,你是兩次釋放貸款對象,這就是爲什麼你得到的錯誤。你只需要釋放一次。fmLoanRequests創建對象,但是您說它可以在fmLoan關閉之前關閉,因此fmLoan應取得對象的所有權並在關閉fmLoan時釋放它。當關閉fmLoanRequest時,不要釋放對象。

另一種方法是定義一個TLoan和後代實現的接口,然後直接傳遞ILoan而不是TLoan。界面被引用計數,所以貸款對象將被自動釋放,並且只有一次,fmLoanRequestsfmLoan已經釋放它們對它的引用。

+0

我誤解了Assigned()的工作有點像Java中的垃圾收集器(測試** Referenced Object **是否有其他引用),這顯然是不正確的 - Assigned()測試引用變量是否仍然存在某個地址(有效與否) –

+0

在Delphi中沒有垃圾回收,'Assigned()'只是檢查指定的指針是否爲nil,其他都沒有,但是在移動平臺上,Delphi確實有[ARC(自動引用計數)](http: //docwiki.embarcadero.com/RADStudio/en/Automatic_Reference_Counting_in_Delphi_Mobile_Compilers),TObject在ARC系統上具有RefCount和Disposed屬性 –

1

我已經添加了這條線,以確保如果fmLoan沒有出於某種原因處理它,該對象將被釋放。我意識到這個對象已經被釋放了,但是if Assigned()不應該阻止不必要的對象釋放嗎?

這是一個關鍵的誤解。考慮下面的程序:

{$APPTYPE CONSOLE} 

var 
    obj: TObject = nil; 

begin 
    Writeln(Assigned(obj)); 

    obj := TObject.Create; 
    Writeln(Assigned(obj)); 

    obj.Free; 
    Writeln(Assigned(obj)); 

    Readln; 
end. 

此輸出以下:

 
FALSE 
TRUE 
TRUE 

注意,輸出的最後一行是TRUE。換句話說,當您銷燬一個對象時,請調用其方法Free,參考變量未設置爲nil

你的錯誤是,你認爲Assigned測試對象是否已被破壞。它不這樣做。它僅測試參考變量是否爲nil。我們再來看一下更詳細的代碼。

obj := TObject.Create; 

這裏我們創建一個新的對象,分配在堆上,調用TObject.Create。我們還將obj分配給該對象的地址或引用。該行執行後,obj是一個引用變量,其中包含有效對象的地址。

obj.Free; 

這破壞了obj所指的對象。運行析構函數,然後內存被銷燬。在這條線執行後,對象已被銷燬,但obj仍然指那個被破壞並且現在無效的內存塊。這就是爲什麼Assigned(obj)是正確的。

注:我顯然不使用指針。

這是一個有趣的觀點。實際上,每當你使用一個引用變量時,你都在使用指針。儘管語言隱藏了這個事實,但對象引用變量只不過是指向堆中分配的內存的指針。我們使用術語參考而不是指針但實際上這些都是一樣的東西。它們的行爲是一致的,賦值運算符具有相同的語義,但您仍然有可能泄漏,雙重釋放,釋放後訪問以及指針的所有其他缺陷。所以儘管你沒有明確地使用指針,但仍然值得把對象​​引用變量看作是指針。

我爲這個不同的問題寫了一個詳細的答案。我建議你閱讀這個答案:https://stackoverflow.com/a/8550628/505088

一個,你會帶走點就像是

if Assigned(oLoan) then 
    oLoan.Free; 

代碼是毫無意義的。 Free方法還檢查對象引用是否爲nil。該行代碼實際上是擴大到:

if Assigned(oLoan) then 
    if Assigned(oLoan) then 
    oLoan.Destroy; 

所以,與其

if Assigned(oLoan) then 
    oLoan.Free; 

,你只要簡單地寫

oLoan.Free; 

現在,回到了訪問衝突。我認爲現在應該很明顯,你試圖摧毀一個已經被銷燬的對象。你不能這樣做。你需要重新檢查你的生命週期管理。推理如「如果fmLoan沒有出於某種原因處理它」真的不夠好。你需要100%確定生命週期管理。你需要確保你的對象被銷燬一次。無法看到您的所有代碼,我不想提出具體的建議。

有時候有用的一種模式是在銷燬對象時將對象引用設置爲nil。如果物體可能在多處被破壞,那麼這種技術可以用來確保你不會試圖破壞它兩次。你甚至可以使用FreeAndNil輔助函數。但值得強調的是,如果您不確定是否已經銷燬了該物體,那麼這通常表示設計不良。如果您發現自己想要撥打Free以「以防萬一」,那麼您幾乎肯定會做出嚴重錯誤的事情。

+0

謝謝 - 我明白測試Assigned()是等價的Java垃圾收集器的測試,以查看是否有其他位置正在引用此對象(如果是,請保持獨立;否則,可以刪除)。我的錯誤!我欣賞所有解釋和示例 - 我的c頌歌對於那些會更好! –