【问题标题】:Dangling pointer in DelphiDelphi中的悬空指针
【发布时间】:2015-07-09 18:54:46
【问题描述】:

我没有使用接口(所以对象没有引用计数)。这些对象可能被许多其他人引用,我需要处理悬空指针。 FreeAndNil() 不能解决多个引用的问题。我需要当一个对象被销毁时,所有引用它的指针都会自动设置为 nil。或者,它可能类似于 C++ 中 std::weak_ptr 的 Expired() 方法。

我可以实现一个“弱智能指针”来做到这一点,但我不确定它是否是一个过于复杂的实现。你建议另一种解决方案吗?这是我正在考虑的未经测试的可能解决方案:

type
  TWeakReferenceable = class
  constructor Create();
  destructor  Destroy(); override;  //Set ReferencedObject:=nil for all the weak references in FWeakReferenceList
  private
    FWeakReferenceList: TList; //List of weak references to this object
  protected
    procedure RegisterWeakReference(const AWeakReference: TWeakReference<TWeakReferenceable>);   //Adds a weak reference 
    procedure UnregisterWeakReference(const AWeakReference: TWeakReference<TWeakReferenceable>);   //Removes a weak reference
  end;

type
  TWeakReference<TObjectType: TWeakReferenceable> = class
  constructor Create();
  destructor  Destroy(); override; //Destroys the object and calls UnregisterWeakReference(self) for the referenced object 
  private
    FObjectReference: TObjectType;
    procedure SetReference(AReferencedObject: TObjectType); //Calls UnregisterWeakReference(self) for the current reference, updates FObjectReference and calls RegisterWeakReference(self) for the referenced object  
  public
    property  ReferencedObject: TObjectType read FObjectReference write SetReference;
  end; 

【问题讨论】:

  • 附带说明,Delphi 不需要括号用于空参数列表。您可以定义它们,例如 constructor Create; 与它们的用法相同。
  • 我知道,但我喜欢使用它们。我认为它们有助于一目了然地区分方法和属性(在调用它们时也是如此)。当我看到:MyRectangle.Area;它可以是方法或属性,但括号使该信息明确,并为我提供了有关代码行为的额外信息。
  • 首先,我从来没有看到区分方法和属性的重要性。其次,您可以拥有MyRectangle.Area,它是由方法备份的属性。您正在坚持真正无关紧要且高度不可靠的编码实践。
  • 是的,但我很学究。我知道如果没有必要,建议不要写括号。如果括号的使用一直模糊不清,我可能会对该规则有任何问题,但事实并非如此。例如area:=Rectangle.Area,但area 不能是Single 变量,而是在代码顶部声明的类似function () of Object 的方法引用(传递Rectangle.Area 作为参数时相同)。
  • 如果我们必须在函数调用中使用(),这种语言会好得多,因为它可以消除歧义。

标签: delphi weak-references weak-ptr dangling-pointer


【解决方案1】:

对于移动平台,Delphi 对对象使用 ARC(自动引用计数),并且编译器有一个 [weak] 属性用于声明一个弱指针,当引用的对象被释放时,该指针会自动为零。

对于桌面平台,Delphi 不对对象使用 ARC。然而,TComponent 有自己的机制来处理“弱”引用——它的FreeNotification() 方法。当一个组件对另一个组件的生命周期感兴趣时,它必须调用另一个组件的FreeNotification() 方法。 TComponent 维护感兴趣组件的内部列表。当TComponent 对象被释放时,它会调用那些感兴趣的组件的Notication() 方法,这样他们就可以将它们对被释放组件的引用置零。

不过,您显示的代码没有使用TComponent。因此,您必须创建自己的注册/通知系统来消除对已释放对象的引用。

【讨论】:

  • 我会将此标记为已接受的答案,因为提到桌面平台目标缺少弱指针,并建议使用类似于在 TComponent 类上实现的注册/通知系统。
猜你喜欢
  • 2013-01-10
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 1970-01-01
相关资源
最近更新 更多