Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How To Dispose of TListItem.Data And Pointer

729 views
Skip to first unread message

Bill Miller

unread,
Aug 24, 2007, 1:20:17 PM8/24/07
to
Application I am working on shows files and folders from an FTP site in a
TListview. In order to sort the listview to place all the folders at the
top of the listview, a pointer is used to store the original FTP indexes so
that when one clicks on a Listview Item, the actual FTP site's string index
is used instead of the listviews itemindex. Without this, the wrong file or
folder name is selected on the server.

The pointer to the TListview items' data property seems to work fine. The
correct filename or folder is selected on the server when the listview item
is selected.

// The record pointed to by each TListview items' data property
prItemData = ^rItemData;
rItemData = record
integer: integer;
end;

When I fill the List view I call:

List Item := ListView1.Items.Add;
with List Item do
begin
Data := New( prItemData );
{Set the items remote index}
prItemData( Data )^.integer := I;
end;

This too seems to work.

My question is how do I dispose of the pointer when the app closes to
prevent memory leaks? I do not have much experience using pointers.

Regards,

Bill

Remy Lebeau (TeamB)

unread,
Aug 24, 2007, 2:20:40 PM8/24/07
to

"Bill Miller" <w2...@hicomponents00.com> wrote in message
news:46cf135f$1...@newsgroups.borland.com...

> // The record pointed to by each TListview items' data property
> prItemData = ^rItemData;
> rItemData = record
> integer: integer;
> end;

You don't need a record at all when you are storing just a single integer.
You can store the integer value itself directly into the Data property.
Simply typecast it when needed, ie:

ListItem := ListView1.Items.Add;
ListItem.Data := TObject(I);
//...
Index := Integer(ListItem.Data);

> My question is how do I dispose of the pointer when the
> app closes to prevent memory leaks?

If you continue to use a record, then use the ListView's OnDeletion event to
free it when the TListItem itself is being destroyed, ie:

procedure TForm1.ListView1Deletion(Sender: TObject: Item: TListItem);
begin
if Item.Data <> nil then
begin
FreeMem(Item.Data);
Item.Data := nil;
end;
end;

With that said, an alternative approach would be to derive a new class from
TListItem instead and make the value be a new member of that class. Then
you don't have to worry about freeing anything yourself at all. For
example:

type
TFTPListItem = class(TListItem)
public
FTPIndex: Integer;
end;

ListItem := ListView1.Items.Add;
TFTPListItem(ListItem).FTPIndex := I;

If you are using D6 or higher, TListView has an OnCreateItemClass event that
you can use to provide the new class for each item:

procedure TForm1.ListView1CreateItemClass(Sender: TCustomListView; var
ItemClass: TListItemClass);
begin
ItemClass := TFTPListItem;
end;

For you are using D5 or earlier, however, then you have to derive a new
component from TListView and override the virtual CreateListItem() method
directly instead, ie:

type
TFTPListView = class(TListView)
protected
function CreateListItem: TListItem; override;
end;

function TFTPListView.CreateListItem: TListItem;
begin
Result := TFTPListItem.Create(Items);
end;


Gambit


Bill Miller

unread,
Aug 24, 2007, 2:47:46 PM8/24/07
to
Thanks Gambit! Lots of information.

For now I choose to just store the single integer value. I added
ReportMemoryleaksOnShutdown := true; to FormCreate in Delphi 2007 patch 1
and I get "The unexpected small block leaks are 13-20 bytes: String X 1"
What is String X 1? Any suggestion on how to track this down? Using Synapse
and DeveloperExpress components along with a few other components.

Regards,

Bill

Bill Miller

unread,
Aug 24, 2007, 3:14:10 PM8/24/07
to
Isn't the Listview.Data destroyed along with the TListView? No memory leaks
were reported duting my test except a small string leak?

Bill

Remy Lebeau (TeamB)

unread,
Aug 24, 2007, 4:08:10 PM8/24/07
to

"Bill Miller" <w2...@hicomponents00.com> wrote in message
news:46cf27e1$1...@newsgroups.borland.com...

> What is String X 1?

It is telling you that 1 instance of a "String" object was leaked.

> Any suggestion on how to track this down?

You would have to replace the memory manager with the full FastMM from
http://fastmm.sourceforget.net in order to enable full tracing of leaks.
Otherwise, you will have to use an external profiler/checker instead.


Gambit


Remy Lebeau (TeamB)

unread,
Aug 24, 2007, 4:09:14 PM8/24/07
to

"Bill Miller" <w2...@hicomponents00.com> wrote in message
news:46cf...@newsgroups.borland.com...

> Isn't the Listview.Data destroyed along with the TListView?

No. The Data property is just a raw pointer. It has no concept of what
kind of memory (if any) was assigned to it. So it can't free it
automatically even if it wanted to.


Gambit


Bill Miller

unread,
Aug 24, 2007, 4:17:57 PM8/24/07
to
So it is best to call Dispose like this, even though no leak was reported?

procedure TFrmMain.FormDestroy( Sender: TObject );
var
i: integer;
ListItem: TListitem;
begin
for i := 0 to ListView1.Items.Count - 1 do begin
ListItem := ListView1.Items.Item[i];
Dispose( ListItem.Data );
end;
end;

Thanks,

Bill

Remy Lebeau (TeamB)

unread,
Aug 24, 2007, 5:42:22 PM8/24/07
to

"Bill Miller" <w2...@hicomponents00.com> wrote in message
news:46cf...@newsgroups.borland.com...

> So it is best to call Dispose like this

No, that is not best. Use the OnDeletion event like I showed you earlier,
and only if you are actually allocating memory to begin with. If you store
the integer value using a typecast instead, there is is no allocated memory
to free.


Gambit


0 new messages