Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi Seattle: I get an Invalid Pointer operation when freeing an object I created

I use Delphi Seattle.

My problem occurs when I attempt to free an object I created.

I searched in this site (and other sites as well) for answers already posted for this question, but they all are a bit different. According to those discussions, my code should work, but obviously something isn't quite right.

So, I need help...

Flow of execution:

a) in form fmLoanRequest, I create an object based on Class TStorageLoan (a Sub-class of TLoan). The Constructor loads all kinds of values into some of the object's attributes (now shown here).

b) Later, I pass the object's address to another form (fmLoan) to an appropriate public variable. fmLoan is the form where all the user's dealings with the contents of Loan happen. Note that fmLoanRequest remains as is while we're in fmLoan. We'll return to fmLoanrequest when fmLoan closes.

c) The fmLoan form is displayed (and shows the data in the object - all that is working well).

d) When closing fmLoan, a procedure is called to Free the Loan object - if it is assigned (see line 10 of second code snippet). That seems to work OK (no error).

e) The 'Invalid Pointer Operation' error occurs when the code in line 14 below is executed: ( if Assigned(oLoan) then oLoan.Free; ).

I had added this line to make sure the object would be freed if fmLoan didn't for some reason deal with it. I realize that the object has been Freed by this time, but shouldn't the 'if Assgned()' prevent unnecessary freeing of the object?

Partial code from form fmLoanRequest (I added some line numbers for reference)

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;

Partial code from form fmLoan (I added some line numbers for reference)

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;

Should I try a different approach?

Should I just remove that line (line 14 - first code snippet) and hope for the best. That's not at all my philosophy on proper coding!

Am I going at it the wrong way?

Note: I obviously don't use pointers.

Any help would be appreciated!

like image 985
Jack N. Avatar asked Oct 18 '22 14:10

Jack N.


1 Answers

It is clear that you are freeing the Loan object twice, that is why you are getting the error. You need to free it only once. fmLoanRequests creates the object, but you say it can be closed before fmLoan is closed, so fmLoan should take ownership of the object and free it when fmLoan is closed. Don't free the object at all when fmLoanRequest is closed.

The alternative is to define an ILoan interface that TLoan and descendants implement, and then pass ILoan around instead of TLoan directly. Interfaces are reference counted, so the Loan object will be freed automatically, and only once, after both fmLoanRequests and fmLoan have released their references to it.

like image 197
Remy Lebeau Avatar answered Nov 15 '22 10:11

Remy Lebeau