Jump to content
Ruslan

aItem := nil

Recommended Posts

I use a lot of class/pointer variables (e.g. aItem := TItem.Create;  or as iterations in Dictionary or ObjectLists) inside methods as local and temporary variables, at the end of each method I used to write "aItem := nil;" if no longer need that.

In building the application I see a lot of "H2077 Value assigned to 'aItem' never used".

Also in some functions I used to write the default Boolean Result value at the beginning as "False", and the builder show in messages "H2077 Value assigned to <function> never used".

 

What is the right way of freeing the local class variables (without loosing the data) and default function result values?

 

Share this post


Link to post

Normal Delphi objects, using the Windows compiler, does NOT have garbage collection or any kind of automatic memory management like Java, C# etc. 

 

This means if you merely assign "nil" to an object reference, the memory pointed to originally by that reference is still allocated in the heap somewhere, but now "lost" -- you've caused a memory leak(!).  

 

Normal objects should be disposed of by calling the destructor, e.g. 

 

var LMyLocalObj : TSomeClass;

begin

  LMyLocalObj := TSomeClass.Create(...);

  try 

    //do something with LMyLocalObj

  finally

    LMyLocalObj.Free;

    //or if you prefer

   FreeAndNil(LMyLocalObj);

  end;

  // more code perhaps...

end;

 

Setting the reference to nil is a safeguard since if you do not do this then the value of the object reference will point to where the now-freed object used to be.  For a while this may still look valid if accidentally used/derefenced, whereas if you reset the reference variable to nil then trying to dereference it will cause an access violation to be raised to alert you to the misuse.  If there's no further use of the variable however in the current scope then setting to nil of course is redundant and serves no purpose.

 

You should carefully review and ideally check your programs for memory leaks using for example the memory leak checking features of FastMM or some other tool.  (There are several.)

 

All that said, there are forms of automatic memory management available in Delphi on Windows: Interfaces support reference counting based memory management whereby the compiler will automatically free an interfaced object referenced via an interface reference when the enclosing method/function terminates, via code the compiler generates to check the reference count and act when it reaches zero.  You should not manually free an interfaced object as this in turn may also cause an exception when the compiler auto-generated code also tries to free the object.  This is a so-called "double-free" error.  FastMM (or some other tool) can also be employed to help detect this type of mistake.

 

Additionally please note that Embarcadero decided arguably somewhat controversially (in a departure from the behaviour on Windows) to adopt similar semantics for plain objects on the Delphi mobile compilers, this is commonly referred to as ARC ("Automatic Reference Counting", see here).  So, when you write Delphi code and compile for a mobile target, then you do not need to explicitly call .Free() or even set to "nil" since the object will be automatically freed when its reference count hits zero.  However, because of vaious reasons including not least the runtime cost of ARC and the conflicting semantics between the platforms, it looks like Embarcadero is now going to revert to making the mobile compilers behave the same as on Windows after Delphi 10.3 Rio, see here: http://blog.marcocantu.com/blog/2018-october-Delphi-ARC-directions.html

 

I hope that helps.

Edited by ByteJuggler
Further Corrections and clarifications, added a link to ARC documentation on docwiki
  • Thanks 1
  • Confused 1

Share this post


Link to post
2 hours ago, ByteJuggler said:

This means if you merely assign "nil" to an object reference, the memory pointed to originally by that reference is still allocated in the heap somewhere, but now "lost" -- you've caused a memory leak(!).  

I do not need to free the object, I use the variable as a iterator in a Dictionary or ObjectList, so the items in them do not need to be freed.

I don't have problems o memory leaks, all the objects a freed where should be, I have just some messages in building the project.

 

Please read again my question.

Edited by Ruslan

Share this post


Link to post
32 minutes ago, Ruslan said:

I do not need to free the object, I use the variable as a iterator in a Dictionary or ObjectList, so the items in them do not need to be freed.

I don't have problems o memory leaks, all the objects a freed where should be, I have just some messages in building the project.

 

Please read again my question.

Yes, I was responding primarily to "TItem.Create" in your original post in context with the question "What is the right way of freeing the local class variables?".  When applied in context of iterator then obviously the items belong somewhere else already etc.  If your only concern is actually warnings about needlessly assigning nil then either don't do that or turn the warning off. (There's a way to disable most warning messages, I don't know off the top of my head whether and how to disable this particular message.  Also some version of the Delphi compiler emitted as I recall some warnings or hints not entirely when you'd expect it.  What version of Delphi are you using?  If this is why you're seeing this, then ... :classic_sad:)

Edited by ByteJuggler

Share this post


Link to post

You said that the objects were instantiated by calling the constructor. You later say that they are loop variables used when iterating over a collection. So that's a total contradiction. 

 

So, with this new information the simple answer is that you never need to set the loop variable to nil. 

 

We read the question just fine. Please don't tell us to read it again. It's you that should read it again. 

Share this post


Link to post
19 hours ago, David Heffernan said:

You said that the objects were instantiated by calling the constructor. You later say that they are loop variables used when iterating over a collection.

These are just 2 ways of usage (in a constructor "OR" as iterator) as was written

22 hours ago, Ruslan said:

(e.g. aItem := TItem.Create;  or as iterations in Dictionary or ObjectLists)

that is the answer I was expected for iterators

19 hours ago, David Heffernan said:

you never need to set the loop variable to nil

so I guess if a pointer is declared in a method that is used to fill a Dictionary, List or ObjectList than it is not needed to set it to nil at the end

Share this post


Link to post
3 hours ago, Ruslan said:

I guess if a pointer is declared in a method that is used to fill a Dictionary, List or ObjectList than it is not needed to set it to nil at the end

You never need to set a pointer to nil. 

  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×