tags:

views:

357

answers:

6

Is there a way to be sure we hold a useable reference to an object i.e. being sure it has not been already freed leaving that non nil reference dangling.

A: 

Unfortunately there is no way to 100% guarantee that a pointer to anything is still valid, except by meticolously writing the correct code.

Lasse V. Karlsen
+4  A: 

If you're using FastMM4 as your Memory Manager, you can check that the class is not TFreeObject.
Or, in a more standard case, use a routine that will verify that your object is what it says it is by checking the class VMT.

There have been such ValidateObj functions hannging around for some time (by Ray Lischner and Hallvard Vassbotn: http://hallvards.blogspot.com/2004/06/hack-6checking-for-valid-object.html)

Here's another:

function ValidateObj(Obj: TObject): Pointer;
// see { Virtual method table entries } in System.pas
begin
  Result := Obj;
  if Assigned(Result) then
    try
      if Pointer(PPointer(Obj)^) <> Pointer(Pointer(Cardinal(PPointer(Obj)^) + Cardinal(vmtSelfPtr))^) then
        // object not valid anymore
        Result := nil;
    except
      Result := nil;
    end;
end;

Update: A bit of caution... The above function will ensure that the result is either nil or a valid non nil Object. It does not guarantee that the Obj is still what you think it is, in case where the Memory Manager has already reallocated that previously freed memory.

François
@update: so, actually it's not that good of an idea to use it, because depending on the memory manager, it's likely that your address is going to be reused. Therefore it will not give a definitive answer.
Davy Landman
+3  A: 

No. Unless you use something like reference counting or a garbage collector to make sure no object will be freeed before they have zero references.

Delphi can do reference counting for you if you use interfaces. Of course Delphi for .Net has a gargage collector.

As mentioned you could use the knowledege of Delphi or the memory manager internals to check for valid pointers or objects, but they are not the only ones that can give you pointers. So you can't cover all pointers even with those methods. And there also is a chance that your pointer happens to be valid again, but given to somebody else. So it is not the pointer you are looking for. Your design should not rely on them. Use a tool to detect any reference bugs you make.

Lars Truijens
A: 

Standard, no...

That's why VCL components can register themselves to be notified of the destruction of an object, so that they can remove the reference from there internal list of components or just reset their property.

So if you'd want to make sure you haven't got any invalid references their are two options:

  • Implement a destruction notification handler which every class can subscribe to.
  • Fix your code in a way that the references aren't spread around trough different object. You could for instance only provide the access to the reference via a property of another object. And instead of copying the reference to a private field you access the property of the other object.
Davy Landman
+1  A: 

As others have said, no definitive way, but if you manage the ownership well, then the FreeAndNil routine will ensure that your variable is nil if it doesn't point to anything.

mj2008
A: 

It's usually not a good idea to check a reference is valid anyway. If a reference is not valid, your program will crash at the place where it is using the invalid reference. Otherwise the invalid reference might survive longer and debugging becomes harder.

Here are some references to why it's better to crash on an invalid reference. (They talk about pointers in Win32, but the ideas are still relevant):

Otherside