Delphi7,传递对象的接口(interface) - 释放对象时导致无效指针操作

标签 delphi pointers interface

我有一个实现接口(interface)的类,该接口(interface)可供插件使用。 类的声明非常简单。整个应用程序只有该类的一个实例。当调用返回接口(interface)的函数时,它会在检索到的接口(interface)上调用 _AddRef,然后将其作为结果传回。不幸的是,它一直有效,直到我尝试释放对象(请参阅“终结”部分) - 它报告无效的指针操作。如果我将其注释掉,它就可以正常工作(但是 FastMM 报告内存泄漏,因此该对象没有被释放)。

这是函数中返回接口(interface)的代码部分(实际上它是我的“ServicesManager”类的重写 QueryInterface)。

if ConfigManager.GetInterface(IID, obj) then
begin
  ISDK_ConfigManager(obj)._AddRef;
  result:= 0;
end

以及ConfigManager类的代码...

type
  TConfigManager = class(TInterfacedObject, ISDK_ConfigManager)
  private
  ... 
  end;

var
  ConfigManager: TConfigManager;
implementation

...

initialization
  ConfigManager:= TConfigManager.Create();
finalization
  if ConfigManager <> nil then
    FreeAndNil(ConfigManager); //if I comment it out, it leaks the memory but no Invalid Ptr. Op. raises

我做错了什么? 我需要传递对 ConfigManager 的 this 实例的引用。

最佳答案

在处理接口(interface)时,您听到的第一条建议是永远不要将接口(interface)引用与对象引用混合。这意味着一旦您开始通过接口(interface)引用来引用对象,您就不再通过对象引用来引用它。曾经。

原因是第一次分配接口(interface)变量时,该对象的引用计数将变为 1。当该变量超出范围或被分配新值时,引用计数将变为 0,并且该对象将被释放本身。这一切都没有对原始对象引用变量进行任何修改,因此当您稍后尝试使用该变量时,它不是空指针,但它引用的对象已经消失了 - 它是一个悬空引用。当您尝试释放不存在的内容时,您会收到无效指针操作异常。

将您的 ConfigManager 变量声明为接口(interface)。不要自己释放它。完成此操作后,您可以将 TConfigManager 的整个声明移至实现部分,因为该单元之外的任何代码都不会引用它。

此外,几乎没有任何理由提供您自己的 QueryInterface 实现。 (你说你覆盖了它,但这是不可能的,因为它不是虚拟的。)由 TInterfacedObject 提供的应该足够了。您提供的实际上导致内存泄漏,因为您在不应该增加引用计数的情况下增加了引用计数。 GetInterface 已调用 _AddRef(通过执行接口(interface)分配),因此您返回的对象具有过多的引用计数。

关于Delphi7,传递对象的接口(interface) - 释放对象时导致无效指针操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1436198/

相关文章:

multithreading - 线程自动启动

c# - 将 setter 添加到派生接口(interface)

Java : Accessing Hidden Interface Field

c# - 将结构转换为继承自同一接口(interface)的类

delphi - 更改应用程序中的字体

delphi - 确定 TLabel 的宽度

delphi - 有没有 Delphi XE2 样式库?

c - 单链表插入函数

c - 为什么它们都指向同一个地方?

C++ 递归和指针问题