Post by StarkI 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 StarkIf 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