gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 15:39:42 25 4
gpt4 key购买 nike

我有一个实现接口(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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com