How to keep track of the references to an object?

2019-07-05 10:10发布

问题:

In a world where manual memory allocation and pointers still rule (Borland Delphi) I need a general solution for what I think is a general problem:

At a given moment an object can be referenced from multiple places (lists, other objects, ...). Is there a good way to keep track of all these references so that I can update them when the object is destroyed? ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

回答1:

If you want to notify others of changes you should implement the "Observer Pattern". Delphi has already done that for you for TComponent descendants. You can call the TComponent.FreeNotification method and have your object be notified when the other component gets destroyed. It does that by calling the Notification method. You can remove yourself from the notification list by calling TComponent.RemoveFreeNotification. Also see this page.

Most Garbage Collectors do not let you get a list of references, so they won't help in this case. Delphi can do reference counting if you would use interfaces, but then again you need to keep track of the references yourself.



回答2:

I can't quite figure out why you'd want to do this. Surely you would just check a reference in not Nil before using it?

Anwyays, two possible solutions I would consider are:

  1. Have objects manager their own reference counts.
  2. Create a reference counting manager class.

I would probably add AddRef() and ReleaseRef() functions to either the manager or the reference-aware class. You can then use these to check how many references exist at any point. COM does it this way.

The reference-aware class would manage only it's own reference count. The manager could use a Map to associate pointers with an integer for counting.



回答3:

Are you trying to keep track of who's referencing an object so you can clear those references when the object is destroyed, or are you trying to keep track of when it's safe to destroy the object?

If the latter then it sounds like you're looking for a garbage collector. I've never dealt with Delphi so I don't know if there are GCs for it you can use, but I'd be surprised if there weren't.

If the former then a GC probably wouldn't help. If Delphi supports OOP/inheritence (I honestly don't know if it does) you could do something like this (pseudocode):

// Anything that will use one of your tracked objects implements this interface
interface ITrackedObjectUser {
  public void objectDestroyed(TrackedObject o);
}

// All objects you want to track extends this class
class TrackedObject {
  private List<ITrackedObjectUser> users;

  public void registerRef(ITrackedObjectUser u) {
    users.add(u);
  }

  public void destroy() {
    foreach(ITrackedObjectUser u in users) {
      u.objectDestroyed(this);
    }
  }
}

Basically, whenever you add one of your tracked objects to a collection that collection would register itself with that object. When the object is being destroyed (I figure you'd call destroy() in the object's destructor) then the object signals the collection that it's being destroyed so the collection can do whatever it needs to.

Unfortunately, this isn't really a good solution if you want to use build-in collections. You'd have to write your own collection objects (they could just wrap build-in ones though). And it would require to to make sure you're registering everywhere you want to track the object. It's not what I would consider a "happy" solution, though for small projects it probably wouldn't be too bad. I'm mainly hoping this idea will help spawn other ideas. :)



回答4:

Is there a specific reason you want this? Are you running into problems with rogue pointers, or are you thinking it might be a problem one day?

IMHO it will not be a problem if you design your application right, and using the appropriate patterns really helps you.

Some info about patters:

http://delphi.about.com/od/oopindelphi/a/aa010201a.htm

http://www.obsof.com/delphi_tips/pattern.html



标签: oop delphi