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?

Alberto Rossi
  • 1,800
  • 4
  • 36
  • 58
  • 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. – Jerry Dodge Aug 18 '16 at 01:57
  • No worries, everything can be useful to learn :) – Alberto Rossi Aug 18 '16 at 09:38

2 Answers2

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.

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • "Destroy is not intended to be called" this is incorrect. – Free Consulting Aug 18 '16 at 01:19
  • @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? – Jerry Dodge Aug 18 '16 at 01:20
  • 1
    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 :) – Alberto Rossi Aug 18 '16 at 09:40
  • @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 Velthuis Aug 18 '16 at 19:28
  • @Rudy True, and even then, just a simple `inherited;` is all that's needed. It's just simply following the requirements of inheriting classes. – Jerry Dodge Aug 18 '16 at 19:33
  • @JerryDodge: correct. `inherited` is enough, but that *does* call `Destroy` after all. – Rudy Velthuis Aug 18 '16 at 19:47
  • @RudyVelthuis, static `Free` is merely a convenience tool, for the zeroization reason explained by Remy Lebeaus and Allen Bauer below. It isn't meant to create any cult prohibiting calling virtual `Destroy` directly. – Free Consulting Aug 18 '16 at 21:25
  • @FreeConsultng: No, it is not a "convenience tool", using it is good practice because it not only frees you from having to check for `nil`, it also frees you from having to make the error prone decision if you can use `Destroy` directly or if you should use `Free` or even a `nil` check. It avoids DRY as well. All good reasons *always* to use it, even if, in sporadic cases, the nil check may be superfluous, in the current circumstances ( which may even change later). It provides a higher degree of maintainability. – Rudy Velthuis Aug 18 '16 at 21:34
  • @FreeConsulting A chainsaw is also a convenient tool you could use in place of a hand saw. But why would I use a hand saw when I have a chainsaw I could use? – Jerry Dodge Aug 18 '16 at 21:37
  • @Jerry: bad analogy. Surgeons and probably several kinds of craftsmen use fine saws for things you would not want to use a chainsaw for. – Rudy Velthuis Aug 18 '16 at 21:39
  • @Rudy I meant in reference to cutting down a tree (which is what chainsaws are mostly used for). – Jerry Dodge Aug 18 '16 at 22:16
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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 2
    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. – Ken White Aug 18 '16 at 01:00
  • 2
    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()` – Remy Lebeau Aug 18 '16 at 01:26
  • @Remy Perhaps, but what happens if the Constructor itself raised an exception to begin with? I'd say that `Destroy` is only used by people who are overly-confident about their code, which that level of confidence can actually become dangerous. – Jerry Dodge Aug 18 '16 at 01:30
  • I'd also hate to start another war like this one: http://stackoverflow.com/questions/3159376/which-is-preferable-free-or-freeandnil – Jerry Dodge Aug 18 '16 at 01:34
  • 2
    `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`. – Remy Lebeau Aug 18 '16 at 01:39
  • 2
    Allen Bauer blogged about this very topic back in 2006: [Exceptional Safety](http://blog.therealoracleatdelphi.com/2006/11/exceptional-safety_1.html) – Remy Lebeau Aug 18 '16 at 01:41
  • There's also this related debate, which if I recall, David Heffernan even links in his profile as one of his most common referred questions: http://stackoverflow.com/questions/8548843/why-should-i-not-use-if-assigned-before-using-or-freeing-things – Jerry Dodge Aug 18 '16 at 01:42
  • 1
    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. – Jerry Dodge Aug 18 '16 at 01:44
  • Allen's blog said the same thing as David: "*Using the pattern, `if FField <> nil then FField.Free;` is a redundant, as is, `if Assigned(FField) then FField.Free;`*" – Remy Lebeau Aug 18 '16 at 01:45
  • Which is just as redundant as just simply calling *`FField.Free;`* based on how `Free` actually works. – Jerry Dodge Aug 18 '16 at 02:06
  • Not to make any other discussions, but I'm just posting this if it could help. I've taken it from the book > http://prntscr.com/c78laa – Alberto Rossi Aug 18 '16 at 10:23