59

This question is a continuance of a particular comment from people on stackoverflow which I've seen a few different times now. I, along with the developer who taught me Delphi, in order to keep things safe, have always put a check if assigned() before freeing objects, and before doing other various things. However, I'm now told that I should not be adding this check. I'd like to know if there is any difference in how the application compiles/runs if I do this, or if it won't affect the result at all...

if assigned(SomeObject) then SomeObject.Free;

Let's say I have a form, and I'm creating a bitmap object in the background upon the form's creation, and freeing it when I'm done with it. Now I guess my problem is I got too used to putting this check on a lot of my code when I'm trying to access objects which might potentially have been free'd at some point. I've been using it even when it's not necessary. I like to be thorough...

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FBitmap: TBitmap;
  public
    function LoadBitmap(const Filename: String): Bool;
    property Bitmap: TBitmap read FBitmap;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FBitmap:= TBitmap.Create;
  LoadBitmap('C:\Some Sample Bitmap.bmp');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if assigned(FBitmap) then begin //<-----
    //Do some routine to close file
    FBitmap.Free;
  end;
end;

function TForm1.LoadBitmap(const Filename: String): Bool;
var
  EM: String;
  function CheckFile: Bool;
  begin
    Result:= False;
    //Check validity of file, return True if valid bitmap, etc.
  end;
begin
  Result:= False;
  EM:= '';
  if assigned(FBitmap) then begin //<-----
    if FileExists(Filename) then begin
      if CheckFile then begin
        try
          FBitmap.LoadFromFile(Filename);
        except
          on e: exception do begin
            EM:= EM + 'Failure loading bitmap: ' + e.Message + #10;
          end;
        end;
      end else begin
        EM:= EM + 'Specified file is not a valid bitmap.' + #10;
      end;
    end else begin
      EM:= EM + 'Specified filename does not exist.' + #10;
    end;
  end else begin
    EM:= EM + 'Bitmap object is not assigned.' + #10;
  end;
  if EM <> '' then begin
    raise Exception.Create('Failed to load bitmap: ' + #10 + EM);
  end;
end;

end.

Now let's say I'm introducing a new custom list object called TMyList of TMyListItem. For each item in this list, of course I have to create/free each item object. There's a few different ways of creating an item, as well as a few different ways of destroying an item (Add/Delete being the most common). I'm sure it's a very good practice to put this protection here...

procedure TMyList.Delete(const Index: Integer);
var
  I: TMyListItem;
begin
  if (Index >= 0) and (Index < FItems.Count) then begin
    I:= TMyListItem(FItems.Objects[Index]);
    if assigned(I) then begin //<-----
      if I <> nil then begin
        I.DoSomethingBeforeFreeing('Some Param');
        I.Free;
      end;
    end;
    FItems.Delete(Index);
  end else begin
    raise Exception.Create('My object index out of bounds ('+IntToStr(Index)+')');
  end;
end;

In many scenarios, at least I would hope that the object is still created before I try to free it. But you never know what slips might happen in the future where an object gets free'd before it's supposed to. I've always used this check, but now I'm being told I shouldn't, and I still don't understand why.


EDIT

Here's an example to try to explain to you why I have a habit of doing this:

procedure TForm1.FormDestroy(Sender: TObject);
begin
  SomeCreatedObject.Free;
  if SomeCreatedObject = nil then
    ShowMessage('Object is nil')
  else
    ShowMessage('Object is not nil');
end;

My point is that if SomeCreatedObject <> nil is not the same as if Assigned(SomeCreatedObject) because after freeing SomeCreatedObject, it does not evaluate to nil. So both checks should be necessary.

Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • How does `assigned(I)` differ from `I <> nil`? (Note that I do not use Delphi at all :p~) –  Dec 18 '11 at 00:09
  • Assigned is whether or not a variable has been instantiated, whereas nil can be not assigned and still be readable. – Jerry Dodge Dec 18 '11 at 00:11
  • 16
    @pst, `Assigned` is exactly the same as `<> nil` in most cases. The exception is events, where `Assigned` has a bit of black magic to work around issues that could otherwise arise in the form designer (so you *always* need to use `Assigned` to check whether an event is assigned, whereas for anything else `Assigned` and `<> nil` are equivalent). – Joe White Dec 18 '11 at 00:14
  • another way of saying it is nil = an 'empty' type that can be assigned to a variable. – Jerry Dodge Dec 18 '11 at 00:14
  • 15
    No, they usually mean the same thing. The only difference is that if `F` is a function variable returning a pointer, `Assigned(F)` checks whether `F` itself is `nil`, whereas `F <> nil` checks `F`'s result. –  Dec 18 '11 at 00:15
  • @JoeWhite Really? Very interesting, I'll have to try that out. –  Dec 18 '11 at 00:17
  • @hvd, yeah, `procedure of object` is stored as eight bytes (object pointer + code pointer), and `Assigned` only checks one of those two pointers, I don't recall which. That way, the form designer can use the other four bytes to store its own encoded data to keep track of the event handler, without screwing up the component's code that's running inside the IDE. – Joe White Dec 18 '11 at 00:19
  • @JoeWhite Just trying it out, I see that `X <> nil` is rejected by the compiler if `X` is an procedure of object pointer, and `Assigned(X)` checks even less: only two bytes of `X`. –  Dec 18 '11 at 00:25
  • 1
    @JerryDodge, the example in your edit doesn't actually explain anything. What is it you're trying to do? – Joe White Dec 18 '11 at 00:33
  • http://docwiki.embarcadero.com/VCL/en/System.TObject.Free http://docwiki.embarcadero.com/RADStudio/en/Creating,_Instantiating,_and_Destroying_Objects – OnTheFly Dec 18 '11 at 01:07
  • @pst, Assigned is merely semantic "salt" which verifies what instance is not nil – OnTheFly Dec 18 '11 at 01:11
  • @hvd, two bytes? Appears to be faulty, `if Assigned(P) then` produces `cmp dword ptr [ebp-$08],$00` for me (XE/32bit). Its not real function but compiler intrinsic – OnTheFly Dec 18 '11 at 01:20
  • @user539484 It probably depends on the Delphi version, since it's apparently only used for the benefit of Delphi internal designer classes. I tested with Delphi XE, and it does a cmp word ptr ..., $00. –  Dec 18 '11 at 01:24
  • @user539484 Now seeing that you also tested on XE, I simply have no explanation for this, but it's not interesting enough for me to wonder further. :) –  Dec 18 '11 at 01:30
  • @hvd, i managed to reproduce that, it generates `dword` comparison for normal pointers and `word` for method pointer fields. Now i'm curious why. – OnTheFly Dec 18 '11 at 01:34
  • +1. Jerry this is a GOOD QUESTION. Useful not only to you but hopefully to other people. Some of your earlier questions were so narrowly focused that they were not helpful to other people. Keep it up. – Warren P Dec 18 '11 at 13:50
  • So it all boils down to two things: 1) I should presumably know what I'm creating (of course) and thus adding this protection is code clutter, and 2) Freeing automatically looks for nil, which is also identical with checking `assigned()`, which would be practically double or even triple code. But I was hoping for more of an answer regarding does it hurt my app or not if I have this protection. – Jerry Dodge Dec 22 '11 at 01:05
  • My question should have been "Does it hurt the performance of my application to use `Assigned()` when not needed?" – Jerry Dodge Dec 23 '11 at 01:23
  • 3
    @Jerry Dodge - Also consider using FreeAndNil() instead of Free. It will help you a lot!!!! – Gabriel Jun 19 '13 at 16:50
  • @Altar Actually I do use it where it can be of good use (mainly where the pointer could possibly be read later) – Jerry Dodge Jun 23 '13 at 23:57
  • Looking back, at this particular point in time, I still barely knew what `nil` actually meant. It merely means nothing. Absent. Void. Not even empty. Beyond empty. Just... a black hole. `nil` is the equivalent of wanting to make a peanut butter and jelly sandwich, except there's no peanut butter. Not even an empty peanut butter jar. Just not even a jar. Just a jelly sandwich. – Jerry Dodge Feb 20 '18 at 05:55
  • Assigned IS NOT always equivalent to "if x<> nil. See: http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.Assigned "Tip: When testing object events and procedures for assignment, you cannot test for nil, and using Assigned is the right way." – Gabriel Jan 29 '19 at 11:11
  • There are other cases where `thing <> nil` works where `Assigned(thing)` fails. For example `GetActiveConnection() <> nil` compiles, while `Assigned(GetActiveConnection())` does not. – Ian Boyd Mar 03 '22 at 22:12

5 Answers5

139

This is a very broad question with many different angles.

The meaning of the Assigned function

Much of the code in your question betrays an incorrect understanding of the Assigned function. The documentation states this:

Tests for a nil (unassigned) pointer or procedural variable.

Use Assigned to determine whether the pointer or the procedure referenced by P is nil. P must be a variable reference of a pointer or procedural type.

Assigned(P) corresponds to the test P <> nil for a pointer variable, and @P <> nil for a procedural variable.

Assigned returns False if P is nil, True otherwise.

Tip: When testing object events and procedures for assignment, you cannot test for nil, and using Assigned is the right way.

....

Note: Assigned cannot detect a dangling pointer--that is, one that is not nil, but that no longer points to valid data.

The meaning of Assigned differs for pointer and procedural variables. In the rest of this answer we will consider pointer variables only, since that is the context of the question. Note that an object reference is implemented as a pointer variable.

The key points to take from the documentation are that, for pointer variables:

  1. Assigned is equivalent to testing <> nil.
  2. Assigned cannot detect whether the pointer or object reference is valid or not.

What this means in the context of this question is that

if obj<>nil

and

if Assigned(obj)

are completely interchangeable.

Testing Assigned before calling Free

The implementation of TObject.Free is very special.

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

This allows you to call Free on an object reference that is nil and doing so has no effect. For what it is worth, I am aware of no other place in the RTL/VCL where such a trick is used.

The reason why you would want to allow Free to be called on a nil object reference stems from the way constructors and destructors operate in Delphi.

When an exception is raised in a constructor, the destructor is called. This is done in order to deallocate any resources that were allocated in that part of the constructor that succeeded. If Free was not implemented as it is then destructors would have to look like this:

if obj1 <> nil then
  obj1.Free;
if obj2 <> nil then
  obj2.Free;
if obj3 <> nil then
  obj3.Free;
....

The next piece of the jigsaw is that Delphi constructors initialise the instance memory to zero. This means that any unassigned object reference fields are nil.

Put this all together and the destructor code now becomes

obj1.Free;
obj2.Free;
obj3.Free;
....

You should choose the latter option because it is much more readable.

There is one scenario where you need to test if the reference is assigned in a destructor. If you need to call any method on the object before destroying it then clearly you must guard against the possibility of it being nil. So this code would run the risk of an AV if it appeared in a destructor:

FSettings.Save;
FSettings.Free;

Instead you write

if Assigned(FSettings) then
begin
  FSettings.Save;
  FSettings.Free;
end;

Testing Assigned outside a destructor

You also talk about writing defensive code outside a destructor. For example:

constructor TMyObject.Create;
begin
  inherited;
  FSettings := TSettings.Create;
end;

destructor TMyObject.Destroy;
begin
  FSettings.Free;
  inherited;
end;

procedure TMyObject.Update;
begin
  if Assigned(FSettings) then
    FSettings.Update;
end;

In this situation there is again no need to test Assigned in TMyObject.Update. The reason being that you simply cannot call TMyObject.Update unless the constructor of TMyObject succeeded. And if the constructor of TMyObject succeeded then you know for sure that FSettings was assigned. So again you make your code much less readable and harder to maintain by putting in spurious calls to Assigned.

There is a scenario where you need to write if Assigned and that is where the existence of the object in question is optional. For example

constructor TMyObject.Create(UseLogging: Boolean);
begin
  inherited Create;
  if UseLogging then
    FLogger := TLogger.Create;
end;

destructor TMyObject.Destroy;
begin
  FLogger.Free;
  inherited;
end;

procedure TMyObject.FlushLog;
begin
  if Assigned(FLogger) then
    FLogger.Flush;
end;

In this scenario the class supports two modes of operation, with and without logging. The decision is taken at construction time and any methods which refer to the logging object must test for its existence.

This not uncommon form of code makes it even more important that you don't use spurious calls to Assigned for non-optional objects. When you see if Assigned(FLogger) in code that should be a clear indication to you that the class can operate normally with FLogger not in existence. If you spray gratuitous calls to Assigned around your code then you lose the ability to tell at a glance whether or not an object should always exist.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 3
    @David, in the `TMyObject.Destroy` you are calling `FLogger.Free` without checking if it is Assigned. is that because `TMyObject.Create` will always initialize it to nil when `UseLogging` is False? when declaring a local TObject variable in a procedure, we cannot simply call object.Free without first initializing it. or am I wrong? – kobik Dec 18 '11 at 12:56
  • 4
    @kobik You are 100% correct. An instance of a class is guaranteed to be zero initialized. Local variables are uninitialized. – David Heffernan Dec 18 '11 at 13:10
  • @DavidHeffernan If `Assigned()` can't detect 'dangling pointers' then what can? – Jerry Dodge Dec 22 '11 at 01:13
  • Except of course that you CAN call .update on an unitialised TMyObject. It is a statically linked method that can be called with TMyObject, or any variable declared as TMyObject. – david Nov 29 '13 at 06:12
  • @david You can call it, but what happens next is anyone's guess – David Heffernan Nov 29 '13 at 07:10
  • @David Heffernan ?Are you saying that in current version of Delphi, an object create method must be called "create" or its operation is undefined? – david Dec 01 '13 at 22:52
  • @david No, I'm not saying that – David Heffernan Dec 01 '13 at 22:53
  • 1
    @David Heffernan. Yes, I considered adding "which can be very confusing". But the point is that the answer is wrong: you can call the example .update on the example tmyobject or an object declared but not created as tmyobject, and **since it tests IsAssigned**, the operation of .update is defined, not "anyone's guess". – david Dec 03 '13 at 04:01
  • @david What is the result of Assigned(Self) if the method subject has not been initialised? It could be False, or it could be True. It really is anyone's guess. If a variable is not initialized, it can have any value. My answer is certainly not wrong. – David Heffernan Dec 03 '13 at 07:09
  • 1
    @David Heffernan Not that I want to bang on about it, but the answer still reads "you simply cannot call TMyObject.Update unless the constructor of TMyObject succeeded". I take your point that you assumed a declaration of FSettings that did not imply FSettings was NIL: since the question is about the use of IsAssigned, I made the opposite assumption. – david Dec 05 '13 at 02:04
  • @david My assumption at that part of the answer is that calling a method on FSettings when the instance is nil leads to an error. That's a reasonable assumption. Remember that this answer is of didactic nature. It is trying to teach. Having to explain every little corner case at every step of the way gets in the way of the exposition. When you read the answer just take it as given that none of the methods other than Free can be called on nil refs. – David Heffernan Dec 05 '13 at 07:09
  • 8
    David Heffernan is a living wikipedia :) Thanks for this anser – mca64 Sep 24 '14 at 08:45
  • Empirically, most of time when dealing with dangling pointers my `If not Assigned(obj)` tests did not protected me. So, most of time, `Assigned` will give an false positive. Of course, nothing guarantees that - as mr. Heffernan pointed above. – Fabricio Araujo Nov 09 '15 at 19:28
  • _I am aware of no other place in the RTL/VCL where such a trick is used._ I just encountered one in `TControl.Perform`. – NGLN Dec 20 '15 at 17:47
  • You forgot to mention a very special case. Excerpt from Emba documentation: "Tip: When testing object events and procedures for assignment, you cannot test for nil, and using Assigned is the right way." – Gabriel Jan 29 '19 at 11:10
  • @Rigel My answer only considers object references / pointers. But I don't make that clear. I will edit. – David Heffernan Jan 29 '19 at 11:47
  • @DavidHeffernan - I said it just to make sure that people `won't` think that "Assigned" is `ALWAYS` equivalent to "x<> nil" :) – Gabriel Jan 29 '19 at 11:53
  • @DavidHeffernan You write *The implementation of TObject.Free is very special.*, this is true, but isn't it more important that this behavior is on purpose? I think a quote from (and link to) the documentation should be added. – Wolf Jul 30 '19 at 09:08
  • @Wolf More important than what? I'm not sure a quote from the doc is necessary given that I include the implementation that demonstrates the point incontrovertibly. – David Heffernan Jul 30 '19 at 09:12
  • @DavidHeffernan it's not that I doubt the implementation, and this is obviously an important part of the whole VCL. But the idea to consult the implementation is normally questionable, so I wouldn't start with it. A [documentation section like](http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/System__TObject__Free.html) *[...] System::TObject::Free automatically calls the destructor if the object reference is not nil. [...] Unlike System::TObject::Destroy, System::TObject::Free is successful even if the object is nil [...]* seems more reliable – Wolf Jul 30 '19 at 09:24
  • @DavidHeffernan [this](https://stackoverflow.com/revisions/8550628/7) I find a much better solution. Thanks :) – Wolf Jul 30 '19 at 09:27
23

Free has some special logic: it checks to see whether Self is nil, and if so, it returns without doing anything -- so you can safely call X.Free even if X is nil. This is important when you're writing destructors -- David has more details in his answer.

You can look at the source code for Free to see how it works. I don't have the Delphi source handy, but it's something like this:

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

Or, if you prefer, you could think of it as the equivalent code using Assigned:

procedure TObject.Free;
begin
  if Assigned(Self) then
    Destroy;
end;

You can write your own methods that check for if Self <> nil, as long as they're static (i.e., not virtual or dynamic) instance methods (thanks to David Heffernan for the documentation link). But in the Delphi library, Free is the only method I know of that uses this trick.

So you don't need to check to see if the variable is Assigned before you call Free; it already does that for you. That's actually why the recommendation is to call Free rather than calling Destroy directly: if you called Destroy on a nil reference, you would get an access violation.

Community
  • 1
  • 1
Joe White
  • 94,807
  • 60
  • 220
  • 330
  • Well the question wasn't about nil, it was about `assigned()` which works a little differently – Jerry Dodge Dec 18 '11 at 00:13
  • 3
    Unless you're working with a delegate type (`procedure of object` or `function of object`), `Assigned` is *exactly* the same as checking for `<> nil`. – Joe White Dec 18 '11 at 00:15
  • Well I've had exceptions otherwise... Without me ever setting something to `nil` after I free'd it, I try `if MyObject = nil then` and it's not nil. – Jerry Dodge Dec 18 '11 at 00:17
  • 4
    Well of course. If you do `x.Free`, then `x` still points to the memory address where the object used to be, and both `x <> nil` and `Assigned(x)` will return `True`. So if your variable isn't going out of scope right away, then it's a good habit to set it to `nil` when you free the object it's pointing to. That's why `FreeAndNil` was invented. – Joe White Dec 18 '11 at 00:23
  • Try this in the destructor: `MyObject.Free; if MyObject = nil then ShowMessage('OBJECT IS NIL!');` – Jerry Dodge Dec 18 '11 at 00:25
  • Okay, that would only show a message if `MyObject` was *already* `nil` beforehand. – Joe White Dec 18 '11 at 00:31
  • no but it was created before - according to what you're saying, after freeing `MyObject`, it should be `nil`. But it's not. – Jerry Dodge Dec 18 '11 at 00:33
  • 4
    What on earth did I say that you're twisting to mean "calling `x.Free` will change the `x` variable to point to `nil`"? I've clearly and specifically said the *opposite.* – Joe White Dec 18 '11 at 00:35
  • @user539484, not really -- if it was static, it would be declared as `class procedure Free; static;` and wouldn't have access to the `Self` variable. But it *is* non-virtual, which is important -- you'll get an Access Violation at the call site if you try to call a virtual method on a null reference. In Delphi for Win32, you can actually use this trick on any non-virtual method. (Doesn't work in Delphi for .NET.) – Joe White Dec 18 '11 at 00:50
  • @JoeWhite, yup, not static as in `class method`, but statically bound (to the class, not to the instance). And therefore it works even if instance is `nil`. Of course this trait is specific to Delphi's codegeneration which makes instance pointer an additional parameter to all of methods. – OnTheFly Dec 18 '11 at 01:04
  • Therefore, when you call `Free` without assigning it to `nil` yourself, then `I <> nil` is not the same as `Assigned(I)` because `Free` only checks whether it's nil, and immediately after `Free` is called, it's not nil unless you tell it to be, resulting in an access violation when you try to free :) – Jerry Dodge Dec 18 '11 at 01:22
  • And I don't see why everyone's upvoting an answer which has nothing to do with my question! – Jerry Dodge Dec 18 '11 at 01:23
  • 4
    @JerryDodge: It sounds like you're somehow convinced that `Assigned(I)` has some magic ability to check whether `I` points to an object that's already been freed. It doesn't. Like we keep telling you, `Assigned` checks for `nil`. Try it. `I := TObject.Create; I.Free; if I <> nil then ShowMessage('I <> nil'); if Assigned(I) then ShowMessage('Assigned(I)');` will show two messages: `I <> nil` and `Assigned(I)`. *That's because both checks do the exact same thing.* – Joe White Dec 18 '11 at 01:39
  • @JoeWhite Well what version of delphi are you using? Because we are having opposite results on exact code snippets. – Jerry Dodge Dec 18 '11 at 01:42
  • And the answer still does not even mention the word `assigned` anywhere, and my question is explicitly asking about `assigned`. – Jerry Dodge Dec 18 '11 at 01:45
  • 1
    @JerryDodge, it's true of any version of Delphi from 1.0 to the latest. Here's the docs for the latest version: http://docwiki.embarcadero.com/VCL/en/System.Assigned "System.Assigned: Tests for a nil (unassigned) pointer or procedural variable." – Joe White Dec 18 '11 at 01:47
  • @JoeWhite then A) if that is the case, then somehow my Delphi got messed up, which is pretty far fetched, and B) Your comment above with the code sample is doing the opposite of what you meant for it to do..... – Jerry Dodge Dec 18 '11 at 01:51
  • 3
    @Jerry - Ctrl+Click on `Assigned` in Joe's test code, see if it takes you to system unit. – Sertac Akyuz Dec 18 '11 at 02:23
  • @JerryDodge: If you're seeing `Assigned` do something different than what the documentation says it does, then you should post a new question about that specific issue. Include a code sample that demonstrates the problem. Make sure to say what the *actual output* is that you see when you run your code sample, as well as what you *expected* based on the documentation. (The code in your edit, above, just shows that after `x.Free`, `x` is not nil, which anyone could've told you. You do nothing to explain how you concluded that `Assigned(x)` and `x <> nil` are different.) – Joe White Dec 18 '11 at 02:29
  • I didn't have to mention anything about it until you answered about `nil` instead of `assigned()` I need to try this on another computer tomorrow. – Jerry Dodge Dec 18 '11 at 02:42
  • @Joe Magic has particular meaning with the Delphi compiler. `Free` does not have any compiler magic. Regarding `static`, `Free` is a [static](http://docwiki.embarcadero.com/RADStudio/en/Methods#Static_Methods) instance method. It is not `virtual` or `dynamic`. Therefore it is `static`. You are assuming that `static` refers only to `class` methods. It is unfortunate that the meaning of `static` from the C family of languages leaks into this discussion. – David Heffernan Dec 18 '11 at 10:50
  • @Joe Regarding the magic functions, or intrinsic functions, here's a nice post from RRUZ that lists them: http://theroadtodelphi.wordpress.com/2009/12/24/delphi-compiler-magic-functions-and-procedures/ – David Heffernan Dec 18 '11 at 11:31
  • @DavidHeffernan, I knew about the compiler-magic functions, but wasn't thinking about them when I used the word "magic" here; but that's fair, I'll reword my response so it doesn't confuse anyone. As for Free being static, thanks for the doc reference; I was thinking the `static` keyword, I hadn't realized that the docs still used the word "static" to mean "non-virtual", as well as "static" in the .NET sense. – Joe White Dec 18 '11 at 14:33
21

Why you shouldn't call

if Assigned(SomeObject) then 
  SomeObject.Free;

Simply because you would execute something like this

if Assigned(SomeObject) then 
  if Assigned(SomeObject) then 
    SomeObject.Destroy;

If you call just SomeObject.Free; then it's just

  if Assigned(SomeObject) then 
    SomeObject.Destroy;

To your update, if you afraid of the object instance reference use FreeAndNil. It will destroy and dereference your object

FreeAndNil(SomeObject);

It's similar as if you call

SomeObject.Free;
SomeObject := nil;
Martin Reiner
  • 2,167
  • 2
  • 20
  • 34
  • 5
    +10 for this!! The whole discussion under this topic comes down to the following point: `SomeObject.Free` destroys the instance by calling the destructor chain and releasing the allocated memory. It does **not** change the value of `SomeObject`. Since it is a pointer, i.e. a memory address, it will _still_ bear that very same address _after_ `SomeObject.Free` Moreover, AFAIK, the freed memory is not filled with null bytes as `TObject.InitInstance` does upon construction. So, ideally, use `FreeAndNil( SomeObject )` otherwise there's no chance to tell living instance vars from dead ones – Semanino Sep 27 '17 at 11:15
0

I create a simple example showing my procedure:

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls, FMX.Objects;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Cir : TCircle;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Assigned(Cir) then
  begin
    Cir.Free;
    Cir := Nil;
  end;
  Cir := TCircle.Create(nil);
  with Cir do
  begin
    Parent := Form1;
    Height := 50;
    Width := 50;
    Position.X := 100;
    Position.Y := 100;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(Cir) then
  begin
    Cir.Free;
    Cir := Nil;
  end;
end;

end.
-4

I'm not completely sure of that, but it seems:

if assigned(object.owner) then object.free 

works fine. In this example it would be

if assigned(FBitmap.owner) then FBitmap.free
Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Mariusz980
  • 13
  • 1
  • no it still doesn't work. I mean sometimes it works sometimes it doesn't... as above. – Mariusz980 Mar 16 '16 at 17:00
  • but additionally testing "object <> nil" - also hasnt sorted out the problem... I prefer using another variable fex. "ifcreated_object : boolean". Well, it works fine. – Mariusz980 Mar 16 '16 at 17:06