Dealing with circular strong references in Delphi

后端 未结 4 1116
隐瞒了意图╮
隐瞒了意图╮ 2021-01-18 16:57

I got two classes (in my example TObject1 and TObject2) which know each other via interfaces (IObject1, IObject2). As you probably know in Delphi this will lead to a memory

4条回答
  •  走了就别回头了
    2021-01-18 17:27

    You are solving the wrong problem here.

    Your actual problem is not in strong - weak references nor how your solution can be improved. Your problem is not in how to achieve, but in what you are achieving (want to achieve).

    To directly address your questions first:

    • "TContainedObject(FObj2).Free;" smells a bit, but I don't have a better solution as I need to use an interface to reference to TObject2 (the productive code contains a few inheritance on this end). Any ideas to clean it up?

    You cannot do much here. You must call Free on FObj2 because TContainedObject is not managed class itself.

    • you easily forget to declare all reference between the 2 classes as weak and ..

    You cannot do anything here either. It comes with the territory. If you want to use ARC you have to think about circular references.

    • a similar problem starts to raise with more classes: Having TObject3 which is referenced by one and references the other: memory leak. I could handle it by letting it descent from TContainedObject too but with legacy code this might not be an easy task.

    You cannot do much here either. If your design is really what you want to have, then you will just have to deal with its complexities.


    Now, back to why you are having problems in the first place.

    What you want to achieve (and you have done so with your example code) is keeping whole object hierarchy alive by grabbing any of the object references inside that hierarchy.

    To rephrase, you have Form and a Button on it and you want to keep Form alive is something holds a Button (because Button itself would not function). Then you want to add Edit to that Form and again keep everything alive if something grabs Edit.

    You have few options here.

    • Keep this broken design and live with your solution because you have too much code involved and change would be painful. If you do that keep in mind that this is ultimately broken design and don't attempt to repeat it anywhere else.

    • If you have hierarchy where TObject1 is root class that holds all else, then refactor it and inherit TObject2 from TInterfacedObject to have its own reference counting and don't grab references to FObj2. Instead grab root TObject1 instance and pass that around, if you really need to.

    • This is variation of second approach. If TObject1 is not the root class then create additional wrapper class containing all instances you need and pass that one around.

    Last two solutions are far from perfect and they don't deal with fact that you probably have classes that are doing too much or similar. But no matter how bad that code might be, it does not even come close to your current solution. And with time you can slowly change and improve those solutions much easier than with your current one.

提交回复
热议问题