Question

I cannot remove an object from TObjectList

Asked by: fedra

Hi.

I want to put some objects in a TObjectList. I want to keep the objects in memory after this TObjectList is destroyed so I MUST keep the OwnsObjects= false.

I load the objects like this:


-------------------

GetCub is like this:

function TCubList.GetCub(Poz: Integer): TCubObj;                                
begin
 Result:= TCubObj(self[Poz]);
end;


[Delphi 7]

type TCubList = class(TObjectList)
 
procedure Something;
var LCub: TCubList ;
    NewCub: TCubObj;
begin
 repeat 
  NewCub:= TCubObj.Create; 
  Error:= NewCub.ImportFile;
  if Error<> '' then                   { if error loading this file then don't add it to the list }
     begin 
       FreeAndNil(NewCub);
       Continue;
     end;
  LCub.Add(NewCub);        
 until something;
 
 for x:= Lcub.Count-1 downto 0 DO
  begin
    Cub:= LCub.GetCub(x);
    if Cub.Vec.Count= 0 then then  
       begin 
         Lcub.Remove(Cub);
         Cub.Free;                                   <-------- HERE EInvalidPointer ERROR
       end;
   end;
end;

                                  
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:

Select allOpen in new window

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2008-12-11 at 10:12:23ID23977014
Tags

Delphi 7

,

raised exception class EInvalidPointer with message 'Invalid pointer operation'. Process stopped. Use Step or Run to continue.

Topics

Delphi Programming

,

Free Pascal

Participating Experts
5
Points
50
Comments
53

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. Dynamic access to object method in TObjectList
    I have a TObjectList populated with objects that are, at this time, all descendants of a common ancestor. This is not always going to be the case so I would like to dynamically (run-time) query the objects to determine if they have a particular method present. So, TObjectList...
  2. 'Specific' TObjectList
    After having used TObjectList, I attempted to create a 'specific' TObjectList where you can dictate what items the list holds when created. The code was as follows... type TSpecificObjList = class(TObjectList) private FListObjType: TObject; public constructor c...
  3. Sorting a TObjectList - Help!
    I have a TObjectList which i need to sort. The Objects in it are home-made Objects called TFAs: stupid name, but what the hey. This is a TFA: TFA = class(TObject) iIndex, iHeight, iWidth, iSize: integer; end; My calling code is simply: oUnplaced.Sor...
  4. Is there Bug in D7 about TObjectList / TList ?
    Hallo Experts, I'm using Delphi 7, is there any bug and patch for it's TObjectList / TList thingy ? because I'm having problems using them. Especially related to freeing the Items it contain, is there a bug in Delphi 7 ? Thank You
  5. Need to override Add and Remove method of TObjectList. …
    I need to override Add and Remove method of TObjectList. Problem is that it was not declared as virtual. So, how to do it? I know I can create new methods that can be called but allows room for mistakes since the "old" add and remove methods can be called by mistake.
  6. Frames in a TObjectList (problems with...)
    Hi All, Alright you lovely people your my final option, I've tried and I can't see what I have wrong. I have a TFrame on a form. This frame is to contain other dynamically created frames. My system goes like this. I have a management class & a frame template. I have...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: SteveBayPosted on 2008-12-11 at 10:21:41ID: 23150810

I think you would be better off using a TList rather than a TObjectList.  TList holds pointer but does not own or manage the object it hold references to.

 

by: fedraPosted on 2008-12-11 at 10:38:37ID: 23150947

But isn't the same when you set OwnsObjects to False?

 

by: fedraPosted on 2008-12-11 at 10:47:06ID: 23151019

Ok. Changed to TList. The error is still there.
:(

 

by: fedraPosted on 2008-12-11 at 11:58:18ID: 23151642

Solved by restarting Delphi/deleting DCU's and rebuilding the project (I don't know for sure which of these actually solved the problem).

 

by: fedraPosted on 2008-12-11 at 12:15:52ID: 23151775

Sorry. Problem not solved!

I removed FastMM4 from my Uses clause and the code worked (probably Delphi didn't see the change until I rebuilt). Now that I added the FastMM, the problem is back.

So I still need help with this one. Points increased.

 

by: SteveBayPosted on 2008-12-11 at 13:43:20ID: 23152678

I don't use FastMM so I cannot comment on that.
Your code does not show what  Cub is. I aaume that it is a TCubObj  Here are some things to try though to be honest I don't really think they should make a difference:

 for x:= Lcub.Count-1 downto 0 DO
  begin
    Cub := TCubObj( LCub.GetCub(x)); // <--- Cast as TCubObj
    if Cub.Vec.Count= 0 then then
       begin
         Cub.Free              // <--- Try Free before Delete
         LCub.Delete(x);    // <--- Should do the same thing as remove it's just the way I would do it.
       end;

 

by: fedraPosted on 2008-12-11 at 14:04:36ID: 23152894

GetCub is like this:

function TCubList.GetCub(Poz: Integer): TCubObj;                                
begin
 Result:= TCubObj(self[Poz]);
end;

 

by: AndersonCarliPosted on 2008-12-11 at 23:11:49ID: 23155487

Use Extract() instead Remove().

But remove should work... Are you sure that OwnsObjects is False?

Take a look in Notify() method of TObjectList. it free the object when Action:TListNotification is
lnDeleted but not when is lnExtracted.

If you look inside TList.Extract and remove you'll see that Extract send a lnExtracted Notifiy Action and Remove() sends a lnDeleted

 

by: fedraPosted on 2008-12-12 at 05:36:14ID: 23156999

Ok. I have tried only Cub.Free and still get that "Invalid pointer op".
The question is why the problem appears only when I use FastMM4?
As I said above, the code works (this is why I though for few hours that the problem was solved) if I remove FastMM4.

 

by: rllibbyPosted on 2008-12-12 at 07:34:42ID: 23157995

Have you followed the usage instructions for FastMM4?

<quote>
Usage:
 Delphi:
  Place this unit as the very first unit under the "uses" section in your
  project's .dpr file.
<end quote>

If you don't follow this, you may end up mixing the memory managers which could cause the issues you are seeing. Just a thought...
---

Russell

 

by: fedraPosted on 2008-12-12 at 07:38:24ID: 23158033

"Place this unit as the very first unit under the "uses" section in your project's .dpr file."

Yes. I uses it since 2007. It works really well with other projects. Unfortunately FastMM is free and the support is poor.

 

by: rllibbyPosted on 2008-12-12 at 07:55:59ID: 23158256

I use it as well, and have not had any issues with it. Most likely there is a pointer bug in your code. (stale pointer usage / double free / etc). I would suggest enabling full debug mode for FastMM. If you can narrow down the code (while still reproducing the error), then posting it here would also help.

Russell

 

by: fedraPosted on 2008-12-12 at 07:59:57ID: 23158306

I already activated the fulldebugmode 1-2 weeks ago.
FastMM4 generates an incredible large leak memory report which is never the same.
No single other leak detector can detect those leaks.

 

by: fedraPosted on 2008-12-12 at 08:03:07ID: 23158337

When an "Invalid pointer operation" appears?
What does it means?

My application is vary large (about 10 forms and over 20-30 other units), I cannot post it here.

 

by: rllibbyPosted on 2008-12-12 at 08:26:20ID: 23158570

This is caused because the memory manager has raised an EInvalidPointer exception.

>> from the help <<
EInvalidPointer is raised when an application attempts an invalid pointer operation. For example, it can occur if an application tries to dispose of the same pointer twice, or refers to a pointer which has already been disposed of.
<<

This type of error is ONLY thrown by the memory manager. As stated above, the most common occurrence is a double free on an object. It can also occur if a free'd object is later referenced, although it can be difficult to track. Take the following code (with intended pointer error) that executes without raising an exception.

var  objList:       TObjectList;
     strmMem:       TMemoryStream;
     dwIndex:       Integer;
begin

  objList:=TObjectList.Create(False);

  for dwIndex:=0 to 5 do
     objList.Add(TMemoryStream.Create);

  for dwIndex:=Pred(objList.Count) downto 0 do
  begin
     strmMem:=TMemoryStream(objList[dwIndex]);
     objList.Delete(dwIndex);
     strmMem.Free;
     strmMem.Size:=0; // <- This runs, but is a stale pointer BUG due to the object being freed
  end;

  objList.Free;

end;

 

by: fedraPosted on 2008-12-12 at 08:33:53ID: 23158662

There could be something wrong in the way I created those objects and insert them to the list? I REUSE the NewCub var to load more than one file from disk. Everything is fine. Right?

(full code into my initial post)
 repeat
  NewCub:= TCubObj.Create;
  Error:= NewCub.ImportFile;
  if Error<> '' then                   { if error loading this file then don't add it to the list }
     begin
       FreeAndNil(NewCub);
       Continue;
     end;
  LCub.Add(NewCub);        
 until something;

I also tried to get rid of the NewCub var and work directly with the LCub list:
TCubObj(LCub[x]).ImportFile
but I get the same error.


-------------------------------


I loaded two NewCubs into the LCub list and looked at their memory location using the @ operator.
Both have a unique address and also looking inside the object, all its data/fields are ok.
So, if the memory of those two objects is not overwritten, why I can't destroy them.
Note: If I remember correctly, in a test made few days ago, I can Free the first object (the one located at index 0 in LCub list) but not the last one.




PS: Points increased to 200.

 

by: fedraPosted on 2008-12-12 at 08:40:29ID: 23158719

"    strmMem.Free;
     strmMem.Size:=0; // <- This runs, but is a stale pointer BUG due to the object being freed"
rllibby


This is why I replaced one week ago all .Free operators with FreeAndNil, in the whole program (as you can also see in my initial piece of code).
From what I know, your code should immediately raise and error if the strmMem is free and NIL.

Anyway, the code where this problem appears is short and as you can see there is no place where a double call to FREE appears.

 

by: rllibbyPosted on 2008-12-12 at 10:27:37ID: 23159672

You have something going on... really hard to say without seeing full code.

Anyways, while my example SHOULD raise an exception, if you run it you will find that it DOES NOT. As already stated, pointer bugs can be insiduous and difficult to track. If you want to ensure that you don't have a double free going on behind the scenes, you could write a simple override class like below:

type
  // Your existing class definition
  TCubObj           =  class(TObject);

  // Overriden example for testing
  TCubObjEx      =  class(TCubObj)
  private
     // Private declarations
     FFreeCount:    Integer;
  protected
     // Protected declarations
  public
     // Public declarations
     constructor    Create;
     destructor     Destroy; override;
  end;

constructor TCubObjEx.Create;
begin

  // Perform inherited
  inherited Create;

  // Set free counter
  FFreeCount:=0;

end;

destructor TCubObjEx.Destroy;
begin

  // Resource protection
  try
     // Increment free counter
     Inc(FFreeCount);
     // Display message
     MessageBox(0, PChar(Format('(%p) TCubObjEx.Destroy(%d)', [Addr(Self), FFreeCount])), nil, MB_OK);
  finally
     // Perform inherited
     inherited Destroy;
  end;

end;

then in places where you are using TCubObj.Create, you would use TCubObjEx.Create (or you could add the logic from above into your existing class, choice is yours). This will visually show you the number of times the destructor is getting called.

Russell


 

by: fedraPosted on 2008-12-12 at 11:29:17ID: 23160217

"Anyways, while my example SHOULD raise an exception, if you run it you will find that it DOES NOT" rllibby.

Did you actually tried to run that code? Because on my Delphi 7 it gave me this error (no FastMM):

---------------------------
Project1
---------------------------
Access violation at address 00000018. Read of address 00000018.
---------------------------
OK  
---------------------------

If I activate FastMM, the AV is in "kernel32".


.


If I replace the FREE with FreeAndNil (as explained above) the error is:

---------------------------
Project1
---------------------------
Access violation at address 0041D6D1 in module 'Project1.exe'. Read of address 00000000.
---------------------------
OK  
---------------------------

 

by: fedraPosted on 2008-12-12 at 11:37:44ID: 23160303

Sorry, I missed your post about checking for double free in the destructor.
Thanks for the idea. I will try it right away. If there is a double free attempt then your destructor should catch it.

One question: there is a special reason to override that class? Or I can insert the code directly into the TCubObj?

 

by: rllibbyPosted on 2008-12-12 at 11:43:50ID: 23160358

I'm running D5, and I never post code without first testing. If you had checked my background you wouldn't even ask that question. And you **MISSED** the whole point to begin with.

Because the heap is managed by Delphi (using default or fast MM), a free does nothing more than run the destructor and return the memory back to the  managed heap. The memory is STILL allocated by the heap (unless / until the heap block is returned to the OS via a VirtualFree call), so in windows terms the memory is still valid. So while on your D7 system you get an exception, on a D5 system you don't. The **POINT** being that pointer bugs do not necessarily raise an exception on the line of buggy code. Did you even bother to check for double-free's using the code provided?

I would also suggest that you evaluate what you are asking for. You have pointer issues, and are expecting assistance without providing code to test/validate against.

 

by: rllibbyPosted on 2008-12-12 at 11:55:11ID: 23160472

>> then in places where you are using TCubObj.Create, you would use TCubObjEx.Create (or you could add the logic from above into your existing class, choice is yours). <<

let me restate again...

>> or you could add the logic from above into your existing class, choice is yours <<

 

by: fedraPosted on 2008-12-12 at 11:57:15ID: 23160493

"while my example SHOULD raise an exception, if you run it you will find that it DOES NOT"

Hey! My question was valid as the experiment shows something different that you were saying.
There is nothing wrong in questioning the information before entering it into the brain :)
If you say that you tested the code, I believe you. It just means that Delphi 5 and 7 behave in different way. There is no reason to get upset :)

---------

I will try the code you provided (the destructor) right away.

Is also my intention to fix this problem but I cannot upload the full program here. As I already explained it is really large.

 

by: rllibbyPosted on 2008-12-12 at 12:01:29ID: 23160529

I'm not upset, I just don't have time to waste helping someone that did not acknowledge the advise, or take the time to read what I had already posted.

 

by: fedraPosted on 2008-12-12 at 13:18:14ID: 23161172

"If I replace the FREE with FreeAndNil (as explained above) the error..."

Sorry, but other people confirmed what I said: trying to access an object after you pass it to FreeAndNil will raise ALWAYS and error!

 

by: fedraPosted on 2008-12-12 at 13:37:35ID: 23161315

I have placed your code into the Destructor and I have found that no objects are freed twice. So, this is a good.
However, I have found that all released objects have exactly the same address: 0012FC04.

Plus I have monitored the memory taken by the application. Every time I used that procedure that *may* have the bug, the memory raises from 6.22 to 20MB. But after the procedure exits, the memory returns to 6.22. I have run the procedure 20-30 times and the memory was always released. So I think there is no leak.

 

by: AndersonCarliPosted on 2008-12-14 at 20:16:35ID: 23171175

Hi Fedra:
Did you tried to use Extract() instead Remove()?

 

by: MerijnBPosted on 2008-12-15 at 03:14:08ID: 23172353

Show a little bit more code, something about the constructor of TCubList.
Can you make a little project which reproduces this behavior?
Also, try installing the trial of Eurekalog: www.eurekalog.com
It has a memory leak detection which works quite well.

 

by: fedraPosted on 2008-12-15 at 05:14:52ID: 23172963

Hi.
1) As I explained above, I tried to free the object directly, without calling Extract or Remove and is still not working.
It looks like there is a problem in freeing the TCubObj object and not in TCubList.

2) I didn't changed the constructor/destructor of TCubList. TCubList has just few extra properties that help me to access easily its items.

3) I think I stated this also above: only when I use FastMM4 (latest version) I have this "invalid pointer" error. If I remove FastMM, the program works perfectly (it worked for 3 years). No single other memory debugger can detect the leaks that FastMM detects (I have tried other 4, including Eureka).

4) As you have asked, the code will come soon.

 

by: MerijnBPosted on 2008-12-15 at 05:21:17ID: 23173016

what options do you have set for FastMM if you use it. Any more info in the exception (what addresses)?

 

by: fedraPosted on 2008-12-15 at 05:38:17ID: 23173151

As rllibby instructed, I added his piece of code in the destructor of TCubObj. It is not Freed twice! So the problems is not here. Anyway, as you can see from my code, there is no place where Cub.Free is called twice.

Points increased.
Thanks for help guys!


TYPE
 TCubList = class(TObjectList)
   private
   protected
   public
     function  GetCub(Poz: Integer): TCubObj;                                  
     function  AllDeadOrDone: Boolean;
     function  AllHaveChroma: boolean;                                         
     procedure FreeObject(Poz: Integer); overload;                             
     procedure FreeObject(Obj: TCubObj); overload;                             
     procedure SortByPosInGrid;
 end;
 
procedure TCubList.FreeObject(Poz: Integer);                                    
var Cub: TCubObj;
begin
 Cub:= GetCub(Poz);
 FreeAndNil(Cub);
 Delete(Poz);
end;
 
 
procedure TCubList.FreeObject(Obj: TCubObj);                                    
begin
 Extract(Obj);                                                                  
 FreeAndNil(Obj);
end;
 
 
function TCubList.GetCub(Poz: Integer): TCubObj;
begin
 Result:= TCubObj(self[Poz]);
end;
 
 
 
{-------------------------------------------------------------------------------
                                    USING LCUB
-------------------------------------------------------------------------------}
 
 
 
procedure Start;
begin
 LCub:= TCubList.Create(FALSE);                                                 { FALSE means OwnsObjects= FALSE }      {# only in v2}
 ...
 
 { START }
 InputSp:= 0;
 AlreadyShown:= FALSE;
 REPEAT
   Nume:= InputList[InputSp];
 
   { IMPORT }
   NewCub:= TCubObj.Create;
   WITH FrmSettings DO
    Msg:= NewCub.ImportSp(Name, spn1.Value, spn2.Value, spn3.Value);
 
   { REMOVE INVALID }
   if Msg<> '' then
    begin
     Out2Log('ERROR');
 
     { Move to 'INVALID' folder }
     InvalidFolder:= ExtractFilePath(CntFullName)+ 'Invalid\';
     if ForceDirectories(InvalidFolder) then
      begin
       if FrmSettings.radCopyFiles.Checked                                      
       then FileCopyTo(NewCub.FullName, InvalidFolder+NewCub.ShortName, TRUE)
       else FileMoveTo(NewCub.FullName, InvalidFolder+NewCub.ShortName);
      end; 
 
     InputList.Delete(InputSp);
     FreeAndNil(NewCub);
     CONTINUE;                                                                  { ABORT THIS LOOP }
    end;
   
   { Add cub to list }
   LCub.Add(NewCub);
   
   { CHECK FOR LOW QUALITY }                                             
   if NewCub.GetNrOfBT < 25 then
      begin
       Out2Log('Possible errors while importing');
      end;
   inc(InputSp);  
 UNTIL InputSp>= InputList.Count;      {#END IMPORT}
 
 
 LCub.GetCub(ctRefPos).IsRef:= UseRef;
 
{=============================================================================
| =                                   BLOCK                                = |
 =============================================================================                                                                                      }
 TRY
  { COMPARE }
  for x:= 0 TO Lcub.Count-2 DO
    for y:= x+1 TO Lcub.Count-1 DO
      FindW(LCub.GetCub(x), LCub.GetCub(y), WSize);
 
  { FREE non match }
  for x:= Lcub.Count-1 downto 0 DO
   begin
    Cub:= LCub.GetCub(x);
    if Cub.VList.Count= 0 then
     begin
       if Cub.IsRef
       then begin
              Out2Log('Cannot be done');
              Grid.UseRef:= FALSE;
              UseRef:= FALSE;
            end
       else begin
              StringList.Add(Cub.FullName);
              Out2Log('This file has not match');
            end;
 
       { I don't need this file anymore. Free it. }
       //Lcub.FreeObject(Cub);
       //Cub.Free
       //GetCub(x).Free;
       //Lcub.Extract(x)
       //FreeAndNil(Cub)
       *** INVALID Pointer OP HERE ***
       
     end
   end;
 
 ...
 ...
end;

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:

Select allOpen in new window

 

by: fedraPosted on 2008-12-15 at 05:54:17ID: 23173271

MerijnB:
"what options do you have set for FastMM if you use it. Any more info in the exception (what addresses)?"

Is set on full debug - it needs the FastMM_FullDebugMode.dll.
"Invalid pointer op" appears as a dialog box. There is no address or other information. I have found its position in the source code by running the program step by step until that line where I try to free the 'Cub'.

This "invalid pointer" does not appear in FastMM's leak log.

the log may look like this, but is never the same:

------------------------------------------------------
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):
5 - 12 bytes: TIdThreadSafeInteger x 1
13 - 20 bytes: TList x 1
21 - 36 bytes: TIdCriticalSection x 2
37 - 52 bytes: TStringList x 2
85 - 100 bytes: AnsiString x 2
149 - 164 bytes: TCubObj x 2
165 - 180 bytes: Unknown x 1
437 - 484 bytes: AnsiString x 1
533 - 596 bytes: AnsiString x 2
821 - 916 bytes: AnsiString x 1
1013 - 1124 bytes: Unknown x 1
1669 - 1844 bytes: Unknown x 1

The sizes of leaked medium and large blocks are (excluding expected leaks registered by pointer): 162980, 109732, 4260
Note: Memory leak detail is logged to a text file in the same folder as this application. To disable this memory leak check, undefine "EnableMemoryLeakReporting".
------------------------------------------------------

Again: Eureka sees no leaks, except the old one in a TDragAndDrop component - totally unrelated with this stuff (www.melander.dk).

 

by: Geert_GruwezPosted on 2008-12-15 at 23:17:41ID: 23181558

something that strikes me as odd:

procedure TCubList.FreeObject(Poz: Integer);                                    
var Cub: TCubObj;
begin
 Cub:= GetCub(Poz);
 FreeAndNil(Cub);
 Delete(Poz);
end;

you write your own routine to free objects within TCubList when it's allready in the TObjectList ?
why ?

this is basically saying OwnsObjects := True ...
just set OwnsObjects = true and use the Delete(Index) or Delete(IndexOf(AObject));

something people invent something again and again and again and ...
when all they had to do was read the help to see if it existed allready or not

and when a program has a memory leak, and some other program catches it and points to something totally different, maybe the memory leak *is* in the something totally different ...

 

by: Geert_GruwezPosted on 2008-12-15 at 23:26:04ID: 23181601

the second that i would say ...
at first glance you certainly have memory leaks
i tend to make sure i create an object and free it on the same level
i added levels to your code to show the level where you create and the level where your free
this is one of the ways to see visually where you have memory leaks ...
in 95% of the cases i just pinpoint the memory leak with keeping this in mind
because you deleted necessay parts of the code to understand the concept nobody can really help you
but some try ...

you are creating NewCub on Level1 and freeing it on Level2
lets translate it: you are allways creating it on Level1 and
(because of the if) sometimes deleting it on Level2
 
  // level 1
  { IMPORT }
  NewCub:= TCubObj.Create;
  WITH FrmSettings DO
    Msg:= NewCub.ImportSp(Name, spn1.Value, spn2.Value, spn3.Value);
 
  { REMOVE INVALID }
  if Msg<> '' then
  begin
    // level 2
   Out2Log('ERROR');
   { Move to 'INVALID' folder }
   InvalidFolder:= ExtractFilePath(CntFullName)+ 'Invalid\';
   if ForceDirectories(InvalidFolder) then
   begin
      // level 3
      if FrmSettings.radCopyFiles.Checked then
        FileCopyTo(NewCub.FullName, InvalidFolder+NewCub.ShortName, TRUE)
      else
        FileMoveTo(NewCub.FullName, InvalidFolder+NewCub.ShortName);
    end;
    // level 2
 
    InputList.Delete(InputSp);
    FreeAndNil(NewCub);
    CONTINUE;                                                                  { ABORT THIS LOOP }
  end;
  // level 1

 

by: Geert_GruwezPosted on 2008-12-15 at 23:30:44ID: 23181620

this is just a guess as you deleted invaluable parts of your code

if you create every instance using a try finally and keep them on the same level you prevent this

aObject := TObject.Create;
try
  if blabla then
  begin
    // etc
  end;
  // etc
finally
  FreeAndNil(aObject);
end;

 

by: MerijnBPosted on 2008-12-16 at 00:21:35ID: 23181837

@Geert_Gruwez:

> you write your own routine to free objects within TCubList when it's allready in the TObjectList ? why ?
> this is basically saying OwnsObjects := True ...

see start post:

> I want to keep the objects in memory after this TObjectList is destroyed so I MUST keep the OwnsObjects= false.

There are of course other options for this, but this is fedra's motivation for doing this.

 

by: Geert_GruwezPosted on 2008-12-16 at 00:24:47ID: 23181848

maybe it would be better for fedra to state in a functional description what is desired of the code
sometimes you start yourself blind on the code without even thinking of what is actually needed

and you end up fixing code that actually needs deleting because a different approach must be used ...

 

by: MerijnBPosted on 2008-12-16 at 00:34:17ID: 23181885

@fedra:

Geert_Gruwez is right with what he says above; it's a very good practice to keep creation and destruction of objects structured.

I noticed two problems in your code, if removed a lot of code below to make it clear where the problem might be.

1)
It's possible you add a nil pointer to your list here. If the last cub was removed because it was invalid (if Msg <> ''), you do FreeAndNil(NewCub).
But in the end, you always add the last NewCub to LCub.

2)
You (probably) let InputSp count from 0 until you break out of the loop (UNTIL InputSp>= InputList.Count). There is one problem though, you both delete from the list (InputList.Delete(InputSp)) and you increase InputSp (inc(InputSt).
This can cause a problem when you are at the last item. To avoid this, it's better to iterate through the list backwards (in other words, set InputSp to List.Count - 1 and keep going (deleting and/or increasing) until InputSp= 0).

procedure Start;
begin
 LCub:= TCubList.Create(FALSE);                                                 { FALSE means OwnsObjects= FALSE }      {# only in v2}
 ...
 
 { START }
 InputSp:= 0;
 AlreadyShown:= FALSE;
 REPEAT
   Nume:= InputList[InputSp];
 
   { IMPORT }
   NewCub:= TCubObj.Create;
 
   { REMOVE INVALID }
   if Msg<> '' then
    begin
     InputList.Delete(InputSp);
     FreeAndNil(NewCub);
     CONTINUE;                                                                  { ABORT THIS LOOP }
    end;
   
   { Add cub to list }
			
   // ========= 1 =========
   LCub.Add(NewCub);
   
   // ========= 2 =========
   inc(InputSp);  
 UNTIL InputSp>= InputList.Count;      {#END IMPORT}
end;

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:

Select allOpen in new window

 

by: MerijnBPosted on 2008-12-16 at 00:35:33ID: 23181887

> and you end up fixing code that actually needs deleting because a different approach must be used ...

This seems to be the case here. I think fedra just can't grasp it here, too many strange things in the setup which makes it hard to help.

On the other hand, this is the best way to learn things, just receiving a proper implementation isn't :)

 

by: Geert_GruwezPosted on 2008-12-16 at 00:37:12ID: 23181894

another thing i tend to avoid : CONTINUE and EXIT
it breaks the natural flow !

it just makes it more difficult to follow a certain flow

but that's just my 2 cents

 

by: MerijnBPosted on 2008-12-16 at 00:41:17ID: 23181911

> another thing i tend to avoid : CONTINUE and EXIT
> it breaks the natural flow !

Nice to notice the different opinions about this. I personally see this as very powerful flow control methods (if not abused of course). Just the same with goto, it's not evil by itself, but you can use it in an evil way.

 

by: Geert_GruwezPosted on 2008-12-16 at 00:59:53ID: 23181989

i have drilled myself in finding the memory leaks on sight the way i explained above.
this resulted in not using exit, break, goto, continue, etc ...
i don't allways rewrite code, just when it gets very complex and when there are problems
i just reformat it, and usually after, it only takes a glance to see where the error is.
sometimes it does require some recoding, and then it's easy to go back to the original code
and pinpoint the error.  try finally is often forgotten in this, and adding it usually pinpoints the error

like this

NewCub:= TCubObj.Create;
try

  if x = y then
  begin
    finally
      FreeAndNil(NewCub);
    end;
  end;

  ... compiler error !

 

by: Geert_GruwezPosted on 2008-12-16 at 01:01:11ID: 23181997

that's what i mean with same level, even the compiler doesn't like it !

 

by: fedraPosted on 2008-12-16 at 05:42:31ID: 23183458

MerijnB.
"But in the end, you always add the last NewCub to LCub."

I don't understand.
Let's say I have two objects and for both (Msg <> '').
In this case, for both I hit the CONTINUE and none is added into the LCub.

Can you explain?

thanks

 

by: MerijnBPosted on 2008-12-16 at 05:44:39ID: 23183478

oops, you're right, my bad

 

by: fedraPosted on 2008-12-16 at 05:45:47ID: 23183484

Geert
"you are creating NewCub on Level1 and freeing it on Level2"


Hi.
You said that my code is wrong. Probably you are right :)
But you never explained how to free the object at level one!

 

by: fedraPosted on 2008-12-16 at 05:55:11ID: 23183543

maybe it would be better for fedra to state in a functional description what is desired of the code

What I want to do is to load and decode some files from disk, find the ones that are somehow similar and display them in a grid. In the piece of code (the top) that I displayed I filter invalid files (few of them may have been incorrectly formatted). I put remaining good files in the LCub. At the bottom of the code, I search for similar files and remove from LCub, those that are not similar. There are many filters like this. In the end only very few files are left in the LCub.

Then I transfer those remaining files from LCub into the grid, in order to display them. This is why LCub.OwnsObjects must be False.

Practically I use LCub as a temporary place to store my files (objects) until I find the files I am interested in.

 

by: Geert_GruwezPosted on 2008-12-16 at 06:07:41ID: 23183626

aha, the bait worked ...
and yer right, i didn't ...

i'll try and do it from the limited code fragments you supplied

reading the code
for the start part :
it looks like you want to move files from a source to a valid destination or an invalid destionation ?
is correct ?

procedure Start;
var 
  // maybe complete this too, so we now which are unit vars, global vars, local vars ... ?
  IsValid: Boolean;
begin
  LCub := TCubList.Create(FALSE); { FALSE means OwnsObjects= FALSE }      {# only in v2}
  try
    ...
    { START }
    InputSp := 0;
    AlreadyShown:= FALSE;
    REPEAT
      Nume := InputList[InputSp];
 
      { IMPORT }
      IsValid := True;
      NewCub := TCubObj.Create;
      try
        // What are you trying to do here ?
        // use a form to give values to the object ?
        // and allways the same values ???
        // is this the same ?
        Msg := NewCub.ImportSp(FrmSettings.Name, FrmSettings.spn1.Value, FrmSettings.spn2.Value, FrmSettings.spn3.Value);
 
        { REMOVE INVALID }
        if Msg <> '' then
        begin
          Out2Log('ERROR');
          IsValid := False;
          { Move to 'INVALID' folder }
          InvalidFolder := ExtractFilePath(CntFullName) + 'Invalid\';
          if ForceDirectories(InvalidFolder) then
          begin
            if FrmSettings.radCopyFiles.Checked then 
              FileCopyTo(NewCub.FullName, InvalidFolder+NewCub.ShortName, TRUE)
            else 
              FileMoveTo(NewCub.FullName, InvalidFolder+NewCub.ShortName);
          end;  // else What if you get an error stating the user doesn't have priviliges  enough to create a directory ?
        end else 
          // i assume the object is valid here ?
        begin
          // i get stuck here 
          // can't see where your going ...
          { CHECK FOR LOW QUALITY }                                             
          if NewCub.GetNrOfBT < 25 then
            Out2Log('Possible errors while importing');
          LCub.Add(NewCub);
        end;
      finally
        if not IsValid // hmm you don't want to delete it when adding to the list (i know not same level)
          FreeAndNil(NewCub);
      end;
      InputList.Delete(InputSp); // you delete it from the list to go to the next item ?
      inc(InputSp);  // ???
    UNTIL InputSp >= InputList.Count;      {#END IMPORT}
 
    ... rest of code is later
    ... feedback ?
 
  finally
    FreeAndNil(LCub);
  end; 
end;

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:

Select allOpen in new window

 

by: Geert_GruwezPosted on 2008-12-16 at 06:17:57ID: 23183713

so your LCub object does the parsing of the files

cleaner way to get to same level of create / delete

NewCub.ImportSp(FrmSettings.Name, FrmSettings.spn1.Value, FrmSettings.spn2.Value, FrmSettings.spn3.Value);

add a property/field to the TCub: IsValidFile: boolean
set it in the ImportSp

at the end of the Import:
delete the invalid ones

with functional description is easy to understand:

what about below approach for storing a list of *good* files ?
it's a bit of pseudo code (doesn't actually compile)
the goodfilelist is in the form and is available as long as the form exists

type
  TForm1 = class(TForm)
  private
    fGoodFileList: TObjectList;
    LoadFilesIntoList;
  public
    constructor Create(AOwner: TComponent);
    destructor Destroy; override;
  end;
  
procedure TForm1.LoadFilesIntoList;
var aFileParser: TFileParser;
begin
  // CleanList;
  fGoodFileList.BeginUpdate;
  try
    fGoodFileList.Clear; // i don't care about the objects getting freed or not ...
    for I := 0 to ListOfFiles.Count-1 do 
    begin
      aFileParser := TFileParser.Create(ListOfFiles[I]);
      if aFileParser.IsGoodFile then 
        fGoofFileList.Add(aFileParser); 
    end;
  finally
    fGoodFileList.EndUpdate;
  end;
end;
  
constructor TForm1.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  fGoodFileList := TGoodFileList.Create(True);
end;
 
destructor TForm1.Destroy;
begin
  FreeAndNil(fGoodFileList);
  inherited Destroy;
end;
 
                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:

Select allOpen in new window

 

by: Geert_GruwezPosted on 2008-12-16 at 06:22:41ID: 23183758

your proc for inserting into the grid would be very easy ...
in pseudo ...

procedure TForm1.PutinGrid;
var I: Integer;
begin
  // Clean grid first off course
  Grid.Recordcount := fGoodFilesList.Count;
  for I := 0 to fGoodFilesList.Count-1 do
  begin
    recordIndex := AddRecord;
    Values[recordIndex, columnName.Index] := TFileParser(fGoodFileList[I]).FileName;
    Values[recordIndex, columnFormatting.Index] := TFileParser(fGoodFileList[I]).Formatting;
    // etc
  end;
end;

no need to bother with freeing of objects any more as the TObjectList handles them
unless off course your ObjectList is not in the same form as your grid ?
you could still move it if it isn't ...

 

by: fedraPosted on 2008-12-16 at 06:56:43ID: 23184104

@Geert

at the end of the Import: delete the invalid ones

We are getting rally far away from the initial point of this thread. The problem is really complex; this is not a tiny 10000 SLOC program. I removed tones of code to make that snippet easy for you to understand it. Dont imagine the problem is as simple as listing the name of some files into a Grid. Very complex mathematical functions are applied to the content of the files. Even if you idea will be better, it will mean rewriting large portions of the program.

Anyway, among many other problems with your code, is that keeping the invalid files in memory until I finish the whole procedure will be a memory disaster. This is why I want to use FastMM.
In the snippet, I posted show only the parts relevant to LCub and NewCub. Lets stick to it.

Thanks anyway for trying. I am still interested to know if it is possible to free the object at the same level where you created. As you said, your code, dont demonstrate it.

 

by: Geert_GruwezPosted on 2008-12-16 at 07:00:55ID: 23184157

very complex mathematical functions ???
for somebody who was the best in school at math at the age of 17,
this doesn't really mean much ...
there were off course better ones in other schools as i just missed the nationwide finals.

 

by: MerijnBPosted on 2008-12-29 at 01:14:01ID: 23254543

If this is still a problem for you fedra, can you make simple demo app which reproduces this problem and upload it please?

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...