4

SITUATION

I am studying Delphi from Marco Cantu's book and I already have experience with OOP because I usually work with Java and PHP. To better understand what I'm reading I've made this test:

type TFraction = class private number: double; num, den: integer; fraction: string; function hcf(x: integer; y: integer): integer; public constructor Create(numerator: integer; denominator: integer); overload; constructor Create(value: string); overload; function getFraction: string; end; 

This is a super easy class that converts a decimal number into a fraction. I'm not including the other parts of the code where I define constructors and functions since they aren't useful for my question. I am creating the object in this way.

var a: TFraction; begin a := TFraction.Create(225, 35); ShowMessage(a.getFraction); //The output of ^ is 45/7 a.Free; end; 

QUESTION

From what I've learnt, I know that I have to get rid of the object once I've used it and in fact I am using the Free. In this way I free the memory and I avoid memory leaks.

By the way I see that I also have the possibility to override a destructor. I don't understand very well the behavior of the Free and the Destroy. I use the Free when I have to get rid of an object that I don't need anymore. When I override a destructor I can free the object and also make other actions?

In short, when is it good to use the Free? And when should I prefer the Destroy?

2
  • Sorry Alberto about the war going on in the answer comments. It's an ancient war which has been going on for decades. But it's an excellent chance for you to learn even more about the topic at hand. Commented Aug 18, 2016 at 1:57
  • No worries, everything can be useful to learn :) Commented Aug 18, 2016 at 9:38

2 Answers 2

7

In general, the destructor is used if you need to do something during object destruction which otherwise wouldn't be done automatically. Like freeing memory that you initialize in the constructor. In your example, there is no need to override the destructor, since (presumably) you don't create anything which needs to be destroyed manually.

Also, keep in mind that Destroy is not intended to be called by you at all - neither internally or externally. Free automatically takes care of calling that for you - with a little extra work going on. Free checks if the object is nil or not, and only calls Destroy if it's not nil.

Take this for example:

type TMyObject = class(TObject) private FSomeOtherObject: TSomeOtherObject; public constructor Create; destructor Destroy; override; end; constructor TMyObject.Create; begin inherited; FSomeOtherObject:= TSomeOtherObject.Create; end; destructor TMyObject.Destroy; begin FSomeOtherObject.Free; inherited; end; 

Just as an added note, the usage I see above is missing something. What if the code between Create and Free raises some exception? The procedure would exit, and it would never be free'd. So instead, you should use a try / finally block...

a := TFraction.Create(225, 35); try ShowMessage(a.getFraction); finally a.Free; end; 

This would ensure that no matter what happens between try and finally, the code between finally and end will always be called.

Sign up to request clarification or add additional context in comments.

11 Comments

"Destroy is not intended to be called" this is incorrect.
@FreeConsulting Can you elaborate on this claim, and also consider replying to Ken's comment to Remy's answer? Can you call it? Yes. Is there ever a reason to directly call it? Not that that I'm aware of. Or are you just looking for reasons to prove something I say wrong like everybody else does?
Thank you very much. I have read the next chapter of the book about memory managment and I have found what you've told me. I am going to use the Free since he "decides" when is the moment to call the destructor. Thanks :)
@FreeConsulting: it is not meant to be called directly, except from an inherited destructor. That is 100% correct. Always use Free, don't call Destroy directly, even if, in some circumstances, you are sure the object is not nil, because that means you must decide, and the circumstances can change. If you always call Free, you don't have to make the decision and can't be wrong.
@Rudy True, and even then, just a simple inherited; is all that's needed. It's just simply following the requirements of inheriting classes.
|
3

By the way I see that I also have the possibility to override a destructor. I don't understand very well the behavior of the Free and the Destroy.

Free() calls the destructor if the object pointer is not nil.

Destroy() is the actual destructor.

I use the Free when I have to get rid of an object that I don't need anymore. When I override a destructor I can free the object and also make other actions?

Yes. The destructor is called when the object is in the process of being destroyed. Overriding the destructor is a good place to perform cleanup actions related to the object that is being destroyed.

In short, when is it good to use the Free? And when should I prefer the Destroy?

You can call Destroy() directly, but it is generally preferred to call Free() instead and let it call Destroy() for you.

11 Comments

Can you provide a specific example of when you would ever need to call Destroy rather than Free? I can't recall ever running across one, and make it a practice never to call Destroy myself; I'd be interested in seeing an exception to that practice I'm missing.
If you know for sure that a given object pointer is never nil (such as a local variable that is wrapped in try/finally), you can call Destroy() directly. When in doubt, call Free() instead. In the RTL/VCL source code, there are some examples (not many, mind you) of Destroy() being called directly. For example, in TComponent.DestroyComponents()
Free() was introduced specifically because of the possibility of a constructor exception, since the destructor gets called automatically. The object memory is zeroed before the constructor is entered, to ensure any uninitialized members will be zero/nil in the destructor. This way, destructor writers do not have to keep track of which members were initialized before the exception. I'm not saying to not use Free(). Most of us (myself included) do. I'm just saying that Destroy() can be called directly when you know it is safe to do so and you don't need to check for nil.
Allen Bauer blogged about this very topic back in 2006: Exceptional Safety
I think the debate here roots to the difference between could and should. I could decide to pour vodka in my car's fuel tank. But should I? I think not, just to be safe.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.