8

What is wrong with this code:

type
  TobjAvisos = class    
  public
    constructor Create;
    destructor Free;
  end;

implementation

constructor TobjAvisos.Create;
begin
  inherited Create;
end;

destructor TobjAvisos.Free;
begin
  inherited Destroy;
end;

It compiles with no warnings but FixInsight returns a Warning: "W522 Destructor without an override directive"

Dalija Prasnikar
  • 27,212
  • 44
  • 82
  • 159
Jlouro
  • 4,515
  • 9
  • 60
  • 91

1 Answers1

15

The problem is that you are expected to override the virtual destructor Destroy. That virtual destructor is what is called by the non-virtual method Free.

As it stands, the only way to destroy your class is to call the destructor directly. But Delphi classes are expected to support being destroyed by way of the Free method.

Your class should be like this:

type
  TobjAvisos = class
  public
    constructor Create;
    destructor Destroy; override;
  end;

Overriding the virtual destructor Destroy is the only way to make your class work correctly with the Free method.

Now, there are two main reasons for using the virtual destructor Destroy and supporting Free:

  1. Free can safely be called on a nil object reference. A destructor cannot. This is essential for the object construction mechanism for exception handling.
  2. Supporting Free allows the object to be safely destroyed even if the run time type of the object is more derived than the compile time type of the object reference.

Some useful reading on related topics can be found here: Why should I not use "if Assigned()" before using or freeing things?

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I was about to reference my old question, then I saw you already did :-) – Jerry Dodge May 28 '15 at 19:47
  • @David. So I create my class as you referenced in your answer with Destroy, but I can still call .Free and the class i correctly "freed" and the memory released ? – Jlouro May 28 '15 at 20:39
  • Yes. The class author overrides `Destroy` and implements any necessary destructor code in that overridden destructor. Consumers of the class call the non-virtual method `Free`. See the answer to which I link for details. – David Heffernan May 28 '15 at 20:41
  • I did. I was reading it. An amazing answer, and easy to read and understand. You should write a book about this. Thanks. – Jlouro May 28 '15 at 20:50
  • 1
    Also, if the constructor raises an exception the virtual destructor Destroy will automatically be called. If it isn't overridden, some resources may not be released in that case. – dummzeuch May 29 '15 at 07:34
  • @skybuck That's simply not true. Calling Free or Destroy will behave exactly the same way in case of a double free/destroy. Calling Free does not set the object reference to nil. The whole point of Free is to allow you easily to write destructors that are resilient to exceptions in constructors. Destructors that can operate on partially constructed instances in other words. – David Heffernan Jan 18 '22 at 06:56
  • 1
    @SkybuckFlying If Self is garbage then you are screwed no matter what, Free or Destroy. Since Free calls Destroy, which is virtual, it is dispatched virtually. If Self is not nil, then Free and Destroy behave identically. You can't check for garbage, so no false sense of security. Let me repeat. *The whole point of Free is to allow you easily to write destructors that are resilient to exceptions in constructors.* – David Heffernan Jan 21 '22 at 12:32
  • The difference could very well be that .Destroy is called at the end inheritance level... while .Free is called at the base/begin inheritance level. That is a huge difference. At least you have been warned ! ;) :) (If there is something wrong with the base level but not the end level free while malfunction or not throw an exception or something like that... while destroy will still indicate a problem since it starts at a higher level... not sure if this was it... but could trying all kinds of combinations, sometime you will run into weird situations in life ! ;)) – oOo Jan 22 '22 at 23:42
  • @skybuck it's likely a defect in your code. As you say yourself repeatedly, your memory is very vague. That's obvious becasue everything you've said here is wrong. You should read the answer linked to in tmmy answer here. It will explain all of the misinformation you have written here. – David Heffernan Jan 23 '22 at 05:00