Discussion:
And a question on objects
(too old to reply)
Stark
2010-06-16 14:14:23 UTC
Permalink
I a trying to better understand how object works. I have this silly
question: I have the following statement:
Ptr:= TAccount(AccountsCombBox.Items.Objects[AccountsCombBox.ItemIndex]);
with wich I intended creating an instance of the object associated to a
specific item in a combobx, whose properties I may use in the application
(Ptr: TPointer).

This is working, but my question is: do I need to free Ptr every time I make
this assignement ? If not, do I create more instances everytime the
ItemIndex gets changed (or the object replaces the previous one) ?

I have more questions, but can anyone reply to this for the moment ? Thanks.
a***@aol.com
2010-06-16 20:50:12 UTC
Permalink
Post by Stark
I a trying to better understand how object works. I have this silly
�Ptr:= TAccount(AccountsCombBox.Items.Objects[AccountsCombBox.ItemIndex]);
with wich I intended creating an instance of the object associated to a
specific item in a combobx, whose properties I may use in the application
(Ptr: TPointer).
This is working, but my question is: do I need to free Ptr every time I make
this assignement ? If not, do I create more instances everytime the
ItemIndex gets changed (or the object replaces the previous one) ?
I have more questions, but can anyone reply to this for the moment ? Thanks.
I presume that a TAccount is either a structure containing data, or is
an object containing methods & data. memory is allocared, either
directly for the structure, or by instantiating the object. The
reference to that memory or object is essentially a pointer (although
in Delphi it may be a typed variable).

A TStrings references (ie contains references to) an array of texts
(Strings[]), and also an array of TObject (Objects[]). You know what
strings are, each TObject is a four-byte value typed in Delphi as a
TObject. But any four byte vale can be stored _provided_ you type-cast
it to a TObject when you store it, and type=cast it to what it really
is, after you recover it from the array of TObject.

A TStrings does not have its own storage for the values, that is
provided by a TStringList on its own, or as part of a TComboBox or
TListBox, etc.

In a TComboBox the Items property is a TStrings. Prior to your
example, code would have filled each element of the TComboBox.Items
with a string to describe the selection available, together with a
reference to the corresponding data structure or object. That
reference in the Objects array will be obtained by allocating memory,
or creating the object. When the combobox is freed (or at Form.Free)
each individual structure memory or object must be freed (by
FreeMem(SomePtr) or SomeObject.Free).

You have to allocate memory or instantiate an object (whose reference
you store in the combobox Objects) only when the contents of the
TComboBox is originally loaded (so the answers to your questions are
No & No). Thereafter you just use that reference. The pointer
reference to a structure, or the reference to a Delphi object is
typecast to a TObject when it is assigned to the Objecs array.

The selected item of a TComboBox is a property called ItemIndex. So in
your example the element of the Objects array (corresponding to the
selected displayed Strings element) has been typecast to a TAccount
and allocated to a variable named Ptr.

In my mind there is some confusion in the typing of your example. If
TAccount is a data structure then Ptr is a pointer and the type-cast
should be by PAccount (ie a pointer to the data structure). If
TAccount is an object, then it should not be assigned to a variable
named Ptr, but to a meaningful name like Acct.

TStrings in Delphi are one of the most useful concepts for relating
strings to values (or vice-versa). I've recently used them to
construct a sparse array (where few of the normally consecutive
elements of an array are used).

Alan Lloyd
Maarten Wiltink
2010-06-16 21:13:52 UTC
Permalink
Post by Stark
I a trying to better understand how object works. I have this silly
Ptr:= TAccount(AccountsCombBox.Items.Objects[AccountsCombBox.ItemIndex]);
with wich I intended creating an instance of the object associated
to a specific item in a combobx, whose properties I may use in the
application (Ptr: TPointer).
This is working, but my question is: do I need to free Ptr every time
I make this assignement ?
No. The above statement is a copy of an existing object _reference_,
and it does not create a new object. So you also do not need to free
it.

The basic rule is simple: Create once, Free once. The case for Create
is actually more complicated, but we can dwell on that later. Free
once is really that simple. You can have any number of pointers to
the same object, but you must Free it exactly once, and once you do
that, you should no longer use any of them, because it is no longer a
valid object. It may appear to work for a bit longer, but don't let
that fool you. Its memory (actually, no longer _its_ memory; it has
reverted to the memory manager) may be reused and overwritten at any
moment.

Matching the Free with the Create for every object you instantiate is
easiest when you do the Free in some complementary location to where
you did the Create. A common pattern is

X:=TX.Create;
try
{ Work X }
finally
X.Free;
end;

where the location is simply the same scope, a block inside some
procedure. Note the try-finally with the Create just before the try
and the Free just after the finally. This neatly ensures that if X
was Created, it will also be Free'd. (If the Create failed with an
exception, there is no object and you should not try to Free it.)
(There is no need to clear the pointer value in X after Freeing the
object, all you have to do is not use X.)

Another pattern is to Create object in the constructor and Free them
in the destructor, or to do so in the TForm.OnCreate and TForm.OnDestroy
event handlers. Every pattern that works will display some measure of
symmetry. The place to Free is a logical opposite to the place that
Creates.

In your case, pointers to objects are stored in the items of a combobox.
It seems likely that they were Created just before that, and the
combobox has the _only_ pointers to them. (This assumes that your Ptr
is a local variable that you simply allow to go out of scope again at
the end of the procedure.) Commonly, one pointer to every object is
thought of as the 'owning' reference, and if you only have one, obviously
that one should 'own' the object. That means that if you ever throw that
reference away, the object should then have been Freed. (If you lose your
last reference without Freeing the object, you can no longer Free it, and
you have a memory leak.)

Having one of many pointer to an object be the owner and all the others
'aliases' (who may go away without the implication that you should Free
the object) is not necessary, but it is very convenient. The alternative
is that at any point where a reference is lost, you need to know if there
are any others left. Just try to think of a scenario for that; you'll
quickly find it extremely inconvenient. If you don't, by all means write
a paper and let us read it.

Coming back to the idea that the references in your combobox are the
owning references to those objects. You are obviously making copies of
those references. You should throw those copies away before they become
invalid. That doesn't necessarily mean that you need to overwrite the
value in Ptr with an obviously invalid one, but you do need to keep
track of the validity of the Ptr reference, and once it becomes invalid,
you should remember that you can no longer use it. This may sound very
severe and impractical, but it is no big deal. You can compare it with
a for loop: after the loop, the loop counter variable is undefined and
you cannot depend on it having any particular value. In the code fragment
above, after Freeing the object X points to, simply stop using X until
you store a new, valid, reference in it. In fact, all code you write
depends on you, the programmer, keeping track of what work has already
been done at any point and what work remains.

Coming back _again_ to the idea that the references in your combobox are
the owning references to those object. At some point, ultimately in the
destructor of your form but possibly sooner, the combobox is going to be
Freed itself. You should Free all the objects it points to before then,
and unless you are going to Free the combobox itself immediately after
that, it's probably a good idea to clear all the pointer values. If the
combobox is going to be around, it is probably an invariant condition of
your program that any references it contains are valid - and if it isn't
(which is possible! A simple Boolean variable might do the trick), well,
it's possible but I've never seen it. (Leaving local variables pointing
into Limbo, on the other hand, is commonplace.)

And, as I said, there should ideally be some sense of symmetry in the
filling and the emptying of the combobox.
Post by Stark
If not, do I create more instances everytime
the ItemIndex gets changed (or the object replaces the previous one) ?
The TStrings object that AccountsCombBox.Items points to, that keeps all
the object pointers in its Objects[] list, doesn't change even if the
combobox's ItemIndex does.

Copying an object reference does not create a new object, it only copies
a pointer. Overwriting a pointer also does nothing special.

Meaning, like the idea that some pointer is the owning reference to a
given object, is added by humans. The computer couldn't care less.

Groetjes,
Maarten Wiltink
Jamie
2010-06-16 23:17:09 UTC
Permalink
Post by Stark
I a trying to better understand how object works. I have this silly
Ptr:= TAccount(AccountsCombBox.Items.Objects[AccountsCombBox.ItemIndex]);
with wich I intended creating an instance of the object associated to a
specific item in a combobx, whose properties I may use in the
application (Ptr: TPointer).
This is working, but my question is: do I need to free Ptr every time I
make this assignement ? If not, do I create more instances everytime the
ItemIndex gets changed (or the object replaces the previous one) ?
I have more questions, but can anyone reply to this for the moment ? Thanks.
You simply over write the existing one that is there how ever, if the
existing one is the only copy of the pointer you have to this chunk of
memory, you must free it before over writing it..


In other words, you're simply over writing the variable that points
to a memory location. If you do not have any other reference to this
location afterwards, you'll have lost memory blocks.. If this is simple
pointer value with in some section of memory that you already have a
managed reference to then it's not a problem...

Keep in mind how ever, when freeing the hosted component, it does not
free the memory these pointers point to, unless ofcourse, you are
building a class to manage that also..
Stark
2010-06-17 15:41:35 UTC
Permalink
I am reading a paper on object oriented programming, but I find it
difficult, coming from a totally different and old approach. So, first of
all I thank you all for your invaluable explanations.

I will now add some information on what I did in my application, so you can
comment on this.
I will also explain that my intent to go deeper into objects is triggerred
this time by an error " access violation" my application raises in some
conditions. Tring to get out of this message raises another message "..
invalid pointer operation". It may well be that this has nothing to do with
my objects.. since up to a month ago and for almost a year the applicartion
has been used with no problem. But I recently added functions and modified a
number of things and I can't track down the changes to understand what I did
to the application.

Anyway, this is what I made (By the way, the objects I am talking of are at
least three. TAccount is one of them and all of them are created similarly).
I have a unit where TAccount is defined as a class, with data attributes and
methods.
Also another class is defined, of type TStrings, which is intended to
contain references of instances of TAccount (TAcctList).
I also have a procedure that does the following:
- creates an instance of TAcctList in a global variable named aAcctList
- accesses a datset and for each record:
- creates an instance of TAccount in a local variable of type TAccount,
named aAccount
- initializes its data with fields from the record
- adds it to the aAcctList object.
the variable aAccount is used only within this proc to fill the aAcctList
( I do not free it. Should I ?)
Similarly, I have two more of this Lists.

My MainForm has a ButtonClick procedure where a 'EntryForm' is created and a
EntryForm.Enter procedure is called. This is how I open the EntryForm window
and start working with this. The Enter procedure creates the TAcctList and
the others Lists objects, calls the above mentioned procedure to initialize
the list with each single TAccount object, creates three comboBoxes
associating each object from the Lists to the items. The key statements are
these:
....
Ptr:= TAccount(itens[i]);
comboBox1.items.AddObjects(Ptr.GetStr,Ptr);
.....
Then, each time a comboBox is used, the event ComboBoxChange contains the
following statement:
Ptr:=TAccount(Combobox1.Items.Objects[Conbobox1.ItemIndex]);

Ptr with its data and methods is then used throuought the program. Ptr shoul
be better called aAcct.

If you held up to this line, you have been heroic (does this word exist in
english?). If not, I will understand!
Comments? (more later...)
BRoberts
2010-06-17 17:06:32 UTC
Permalink
Post by Stark
I am reading a paper on object oriented programming, but I find it
difficult, coming from a totally different and old approach. So, first of
all I thank you all for your invaluable explanations.
. . .
Post by Stark
- initializes its data with fields from the record
- adds it to the aAcctList object.
the variable aAccount is used only within this proc to fill the aAcctList
( I do not free it. Should I ?)
Similarly, I have two more of this Lists.
No because you need the object to persist since it is referenced by your
account list. BTW I presume that you code looks somewhat similar to
for each db record do
aAcct := create a new account object
assign data to aAcct
AccountList.Add (aAcct)

I find visualizing what is going on helpful. Take out a coin, this is the
object that is created by construction - object.Create. Each time you assign
this object to something take out a pen or pencil and point it towards the
coin. When the "something" goes out of scope, is assigned another value or
is destroyed remove the associated pen/pencil. When you execute the object's
Destructor (object.Destroy or object.Free) remove the coin. If you use the
procedure FreeAndNil (objectReference), then remove the coin and the
pen/pencil corresponding to the reference passed the procedure.

If you end up with no coin but one or more pens/pencils then you have
"dangling" references. Not a problem so long as the code never uses one of
these references. A serious problem otherwise.

If you end up with the coin but no pens or pencils, you have a memory leak.
a***@aol.com
2010-06-17 19:43:57 UTC
Permalink
On 17 June, 16:41, "Stark" <***@tin.it> wrote:
<snip>
Post by Stark
Also another class is defined, of type TStrings, which is intended to
contain references of instances of TAccount (TAcctList).
If by "defined" you mean you have stated another object by . . .

TStrings = class(some object) etc

or

TStrings = record etc

Then change its name immediately because Delphi already has an object
named TStrings and you will confuse both it & yourself.

<snip>
Post by Stark
Ptr:= TAccount(itens[i]);
comboBox1.items.AddObjects(Ptr.GetStr,Ptr);
Ptr in a name should only be used when the variable _is_ a pointer,
not when it is an object reference (I know, object references are
really pointers but it helps to separate object references & simple
memory pointers). All variable names should be meaningful, otherwise
your code will not pass the "six months" rule. After six months will I
understand what the hell I have done there <g>.

From what you have said I reckon it is a prime example which should be
using TCollection/TCollectionItem descendents. They are expressly
designed to act as a small (say up to 100-200 records) database.

Get hold of one of Marco Cantu's "Mastering ... " books. In your
situation I would suggest one from the early Delphi series 3, 4, or 5.
They are really first class, going from the simple to the complex.
They really helped me to get started.

Alan Lloyd
Maarten Wiltink
2010-06-18 07:32:46 UTC
Permalink
"Stark" <***@tin.it> wrote in message news:4c1a4227$0$18652$***@reader3.news.tin.it...

[...]
Post by Stark
I have a unit where TAccount is defined as a class, with data attributes
and methods.
Also another class is defined, of type TStrings, which is intended to
contain references of instances of TAccount (TAcctList).
You might want to try TObjectList. Or, as Alan says, TCollection/-Item.

Be careful that by default, a TObjectList wants to own the objects it
contains - free the list and behind the scenes it frees all the objects
in it. If you have three lists and all three are owning, make sure there
are no duplicates across the lists.

By the way, a class is a type in its own right. TAcctList is not of type
TStrings, it is derived from it. (Isn't TStrings an abstract class? Did
you implement your own Strings[] property or did you really derive from
TStringList?)
Post by Stark
- creates an instance of TAcctList in a global variable named aAcctList
- creates an instance of TAccount in a local variable of type TAccount,
named aAccount
- initializes its data with fields from the record
- adds it to the aAcctList object.
the variable aAccount is used only within this proc to fill the
aAcctList ( I do not free it. Should I ?)
You don't free a variable, you free the object. Try really hard to get
your head around the difference, it's very important. So, no; you are
using aAccount only temporarily to get at the object. The object should
stay beyond the lifetime of the variable. You DO NOT free the object at
this point.


<snip tale of usage of object lists>

What you do with your lists and the object is essentially correct.

Groetjes,
Maarten Wiltink
Stark
2010-06-18 22:07:48 UTC
Permalink
Here is my classes declaration:

TAccount = class
DbID : string;
Account : string;
Type : string;
.......................
dsBytd : TTable;

procedure FillRecFromDB(aAccount,aType...........);
end;

TAcctList = class(TList)
destructor Destroy; override;
function getAccount(pos: integer): string;
function isHidden(aAccount: string): boolean;
......................................
end;

At EntryFormClose, I have a statement: aAcctList.Fee (which I understand
will free TAcccount also). Leaving this form, my application go back to the
MainForm. Going back again to the EntryForm, TAccount and TAcctList are
recreated and again instantiated when necessary as I already explained in
one of my previous message.

Today, in one f my tests to understand the cause of the error I get (Access
violation), I suppressed the aAcctList.Free statement and the Access
violation did not occurred, but I need to do more tests to verify this.

I did not used TCollection/TCollectionItem, as Alan suggests, because I
didn't know them and I wouldn't know how to use them. Would you give me an
example ? Anyway, for the purpose of learning, I will look into this. I
found Delphi 5 from Marco Cantù.
a***@aol.com
2010-06-19 06:16:24 UTC
Permalink
There is a fair amount of assumptions I must make in commenting on
your code, including your knowledge of the implications of the code
you quote.
Post by Stark
TAccount = class
DbID : string;
Account : string;
Type : string;
.......................
dsBytd : TTable;
procedure FillRecFromDB(aAccount,aType...........);
end;
TAcctList = class(TList)
destructor Destroy; override;
function getAccount(pos: integer): string;
function isHidden(aAccount: string): boolean;
......................................
end;
At EntryFormClose, I have a statement: aAcctList.Fee (which I understand
will free TAcccount also).
Assuming TAcctList.Items is a list of TAccount, then each & every
TAccount must be Free'd in TAcctList.Destroy, by a call to
TAccount.Free. If you independently Free any TAccount before Free'ing
TAcctList then you should set the reference to nil.
Post by Stark
Leaving this form, my application go back to the
MainForm. Going back again to the EntryForm, TAccount and TAcctList are
recreated and again instantiated when necessary as I already explained in
one of my previous message.
Your use of re"created" & "instantiated" implies that you consider
them different operations, but they are different words for the same
operation.
Post by Stark
Today, in one f my tests to understand the cause of the error I get (Access
violation), I suppressed the aAcctList.Free statement and the Access
violation did not occurred, but I need to do more tests to verify this.
That implies that somewhere you have Free'd an instance of sAcctList
without setting its reference to nil. Free has an inherited action
which is effectively . . .

if <reference-to-object> is not nil then
<reference-to-object>.Destroy;

. . . so an uninstantiated object (ie one initially set to nil by
Delphi, or later set to nil by you after freeing it) will not call
Destroy & thereby trigger an access violation.
Post by Stark
I did not used TCollection/TCollectionItem, as Alan suggests, because I
didn't know them and I wouldn't know how to use them. Would you give me an
example ? Anyway, for the purpose of learning, I will look into this. I
found Delphi 5 from Marco Cantù.
TCollection & TCollectionItem contains the skeleton & glue to make a
list of items in a inherent TList. You must code descendants of both
of these to do the specifics of _your_ list & _your_ items. The only
shortcoming is that one cannot easily sort the items, except by a
rather nasty kludge. An example is rather too long to place in a
posting - I will try to email you with it.

Alan Lloyd
Stark
2010-06-19 15:47:15 UTC
Permalink
I feel I am quite close to better understand it all. To make things clearer
I repeate underneath pieces of my code:

My classes declaration:

TAccount = class
Account : string;
.......................
procedure FillRecFromDB(aAccount,...........);
end;

TAcctList = class(TList)
destructor Destroy; override;
function getAccount(pos: integer): string;
......................................
end;

I have a global variable named aAcctList.

My MainForm creates a so called EntryForm and calls a EntryForm procedure
called Enter where:

- I create the class aAccttList := TAcctList.Create; (and that I why I
said "create")

- I execute the proc FillTheList, that does the following:
- creates an instance of TAccount in a 'local' variable aAccount,
- accesses a ds and for each rec initializes aAccount data with fields
from the rec
- adds aAccount it to the aAcctList object.
- (aAccount is never freed, being a local variable.. WRONG ?)
- (and that I why I said "instantiate")

- I fill a ComboBox List items with another procedure. Here the key
statements:
for i := 0 to aAcctList.Count - 1 do begin
Ptr:= TAcct(aAcctList.Items[i]); // (Ptr: TAccount)
ComboBox1.Items.AddObject(Ptr.getString,Ptr);
end;

- Then I have a ComboBoxChange event routine that does the following:
Ptr:=TAccount(Combobox1.Items.Objects[Combobox1.ItemIndex]);
(The purpose is to work with the Account object chosen in the comboBox)
I use a global variable 'Ptr: TAccount' to instantiate it. Ptr is never
freed (SHOULD?)
(This is because I believe that 'aAccount' is lost outside the
FillTheList procedure. RIGHT ?)

- At EntryFormClose, I free aAcctList and this is its Destroy event:
destructor TAcctList.Destroy;
var
i: Integer;
begin
for i := 0 to Count - 1 do
TAcct(Items[i]).Free; // here I believe I am destrying aAccount
instances
inherited Destroy;
end;

- At EntryFormClose, after freeing aAcctList, I ADDED 'aAcctList:= nil;'
(and also TRIED to free and nil Ptr, but I get 'Invalid pointer operation' .
This is because I already got rid of account object freeing aAcctList?).

You all already gave me plenty of comments and advices. I just wanted to
give the complete the picture of the subject. More comments on what it's
wrong or not advisable or even right, are welcome. Thank you very much.
Jamie
2010-06-19 16:27:10 UTC
Permalink
Post by Stark
I feel I am quite close to better understand it all. To make things
TAccount = class
Account : string;
.......................
procedure FillRecFromDB(aAccount,...........);
end;
TAcctList = class(TList)
destructor Destroy; override;
function getAccount(pos: integer): string;
......................................
end;
I have a global variable named aAcctList.
My MainForm creates a so called EntryForm and calls a EntryForm
- I create the class aAccttList := TAcctList.Create; (and that I why I
said "create")
- creates an instance of TAccount in a 'local' variable aAccount,
- accesses a ds and for each rec initializes aAccount data with
fields from the rec
- adds aAccount it to the aAcctList object.
- (aAccount is never freed, being a local variable.. WRONG ?)
- (and that I why I said "instantiate")
If I understand, you are using the same aAccount object for each item
added to the list? If so, a new instant per object you read in should be
created and not using the same copy.. Also, you don't free the prior
one, just over write it and create another. This is after you have
stored the prior one in the list.
Post by Stark
- I fill a ComboBox List items with another procedure. Here the key
for i := 0 to aAcctList.Count - 1 do begin
Ptr:= TAcct(aAcctList.Items[i]); // (Ptr: TAccount)
ComboBox1.Items.AddObject(Ptr.getString,Ptr);
end;
Looks ok. I do question on what type of "STRING" you're using in the
aAccount class ?, I you should be using a short string and watching out
for over flows in the string when reading items from the DS.. Also,
There maybe an issues with Delphi's use of reference counting on the
system systems that are not short types. the combobox may have a
reference to your string and not a copy.. You want to force a copy so
that when you first clean up your objects, the combobox does not have a
reference copy of a string that does not exist any more. I do think a
short string will solve this questionable area.
Post by Stark
Ptr:=TAccount(Combobox1.Items.Objects[Combobox1.ItemIndex]);
(The purpose is to work with the Account object chosen in the comboBox)
I use a global variable 'Ptr: TAccount' to instantiate it. Ptr is
never freed (SHOULD?)
(This is because I believe that 'aAccount' is lost outside the
FillTheList procedure. RIGHT ?)
PTR should not be freed.. if done, you'll get errors on objects that
are no longer valid. Because you're going to remove the object on your
next piece of code..
Post by Stark
destructor TAcctList.Destroy;
var
i: Integer;
begin
for i := 0 to Count - 1 do
TAcct(Items[i]).Free; // here I believe I am destrying aAccount
instances
inherited Destroy;
end;
- At EntryFormClose, after freeing aAcctList, I ADDED 'aAcctList:= nil;'
(and also TRIED to free and nil Ptr, but I get 'Invalid pointer
operation' . This is because I already got rid of account object freeing
aAcctList?).
You all already gave me plenty of comments and advices. I just wanted to
give the complete the picture of the subject. More comments on what it's
wrong or not advisable or even right, are welcome. Thank you very much.
because the order in which you are using the combobox and freeing the
resources, it's possible the Combobox and it's related event code you
have attached to it is acting on strings and objects that don't exist
before you get around to actually freeing the Combobox.. , you could
unload the combobox first before doing the other stuff to remove doubt.
Maarten Wiltink
2010-06-19 22:16:56 UTC
Permalink
"Jamie" <***@charter.net> wrote in message news:v86Tn.83373$***@newsfe21.iad...
[...]
Post by Jamie
There maybe an issues with Delphi's use of reference counting on the
system systems that are not short types. the combobox may have a
reference to your string and not a copy.. You want to force a copy so
that when you first clean up your objects, the combobox does not have a
reference copy of a string that does not exist any more. I do think a
short string will solve this questionable area.
The combobox will never have an alias to a string that does no longer
exist. Reference counting on long strings does actually work - while
the combobox has its reference, the string will not be disposed.

Jerry would occasionally mention that D4 had problems with this, but
I've never seen them myself in the short time I worked with it, and
they must have been fixed in later versions.

Groetjes,
Maarten Wiltink
Stark
2010-06-20 22:27:32 UTC
Permalink
If I understand, you are using the same aAccount object for each item
added to the list? If so, a new instant per object you read in should be
created and not using the same copy.. Also, you don't free the prior
one, just over write it and create another. This is after you have
stored the prior one in the list.

Yes, I am using the same aAccount
procedure ....................
var
aAccount: TAccount;
begin
while not EOF do
begin
aAccount := TAccount.Create;
aAccount.FillRecFromDB(FieldByName('Bank').AsString, .. );
aAcctList.Add(aAccount);
next; // avanza di un record in Bytd
end;
..............
end;

Questions: do I need to free aAccount before creatinf a new one at each new
record? Since aAccount is a local var, what happens to it exiting the
procedure,?

I am using 'string', meanin long string, I believe.
Jamie
2010-06-21 01:01:10 UTC
Permalink
Post by Jamie
If I understand, you are using the same aAccount object for each item
added to the list? If so, a new instant per object you read in should be
created and not using the same copy.. Also, you don't free the prior
one, just over write it and create another. This is after you have
stored the prior one in the list.
Yes, I am using the same aAccount
procedure ....................
var
aAccount: TAccount;
begin
while not EOF do
begin
aAccount := TAccount.Create;
aAccount.FillRecFromDB(FieldByName('Bank').AsString, .. );
aAcctList.Add(aAccount);
next; // avanza di un record in Bytd
end;
..............
end;
Questions: do I need to free aAccount before creatinf a new one at each
new record? Since aAccount is a local var, what happens to it exiting
the procedure,?
I am using 'string', meanin long string, I believe.
Nothing happens to the objects you create in that way when you
exit the procedure. They will be alive and well in the aAcctList
object.. Keep in mind, at some point, you will need to free them which
is what you are doing later on..

You may want to use short strings in the Taccount object.. Or at
least use a character array.. This will lessen the problem of
dynamically controlled strings that have reference counting. I've seen
cases when you reach for a object via a generic pointer using casting,
things go wrong when cleaning up system strings that is done for you in
the background..

Keep in mind, if you are using "RECORDS" you should be using short
strings or array chars in that record to hold string content. Delphi
does well in saving memory for strings how ever, all strings that relate
to one should be kept in the scope of the code. And if you want to
insure the string will be there out side the code block, use a globle
system string or use a short/char string to be past back.

And if I didn't tell you before? Your use of the links being in the
combobox object list maybe conflicting between the time of when you
destroy the object master list and when you destroy the ComboBox..

for example.
lets say you want to close that form and the combobox happens to
be open at the time. A event could trigger and thus the event get
serviced just after the objects have been removed, leaving the combobox
even code to operate on invalid objects..

Just a thought..
a***@aol.com
2010-06-21 09:11:41 UTC
Permalink
On 21 June, 02:01, Jamie
<***@charter.net> wrote:
<snip>
   You may want to use short strings in the Taccount  object.. Or at
least use a character array.. This will lessen the problem of
dynamically controlled strings that have reference counting. I've seen
cases when you reach for a object via a generic pointer using casting,
things go wrong when cleaning up system strings that is done for you in
the background..
<snip>

But TAccount is an object and will well know how to deal with ansi
strings. But as you pointed out there are advantages in using short
strings in a record. Particularly if you inrend to save them in a
"file of record".

When I have occasion to use strings and want to save the records
(whether with a class or a record) I always use what I call "long
strings", which is effectively a 4-byte integer count of the
characters, followed by the characters of the ctring. And stream write
or read them.

Alan Lloyd

Maarten Wiltink
2010-06-19 08:28:12 UTC
Permalink
"Stark" <***@tin.it> wrote in message news:4c1bee27$0$18988$***@reader5.news.tin.it...
[...]
Post by Stark
TAcctList = class(TList)
[...]
Post by Stark
At EntryFormClose, I have a statement: aAcctList.Fee (which I understand
will free TAcccount also).
Not unless you wrote the code to make it.

TObjectList wants to own its items, TList doesn't. TList _can't_,
because it contains untyped pointers, not object references.

(A TList may in reality contain pointers that happen to be object
references, but the object doesn't know, and it mustn't assume.)

Groetjes,
Maarten Wiltink
Jamie
2010-06-19 11:10:37 UTC
Permalink
Post by Stark
TAccount = class
DbID : string;
Account : string;
Type : string;
.......................
dsBytd : TTable;
procedure FillRecFromDB(aAccount,aType...........);
end;
TAcctList = class(TList)
destructor Destroy; override;
function getAccount(pos: integer): string;
function isHidden(aAccount: string): boolean;
......................................
end;
At EntryFormClose, I have a statement: aAcctList.Fee (which I understand
will free TAcccount also). Leaving this form, my application go back to
the MainForm. Going back again to the EntryForm, TAccount and TAcctList
are recreated and again instantiated when necessary as I already
explained in one of my previous message.
Today, in one f my tests to understand the cause of the error I get
(Access violation), I suppressed the aAcctList.Free statement and the
Access violation did not occurred, but I need to do more tests to verify
this.
I did not used TCollection/TCollectionItem, as Alan suggests, because I
didn't know them and I wouldn't know how to use them. Would you give me
an example ? Anyway, for the purpose of learning, I will look into this.
I found Delphi 5 from Marco Cantù.
Have you followed the rules of calling the "INHERITED" constructor at
the start of the Tacctlist constructor and "INHERITED" at the End of the
destructor of TacctList ?

Also, remember that any pointers TLIST holds needs to be cleaned up
if they are to disappear from your control afterwards.

And for the last note, any object with in is not to be used outside
once the aAcctlist has been freed.
Stark
2010-06-17 15:55:49 UTC
Permalink
Correction: Ptr is defined of type TAccount... (not TPointer)
Loading...