为什么这个TStreamAdapter没有被释放?

2023-12-13

比较这两个片段:

(d as IPersistStream).Save(
  TStreamAdapter.Create(
    TFileStream.Create('test.bin',fmCreate),soOwned),true);
(d as IPersistStream).Load(
  TStreamAdapter.Create(
    TFileStream.Create('test.bin',fmOpenRead),soOwned));

这在第二次失败TFileStream.Create因为第一个没有被破坏。这很奇怪,因为该参数具有唯一的引用,我认为它会在关闭时被破坏Save称呼。所以我尝试了这个:

var
  x:IStream;
begin
  x:=TStreamAdapter.Create(
    TFileStream.Create('test.bin',fmCreate),soOwned);
  (d as IPersistStream).Save(x,true);
  x:=nil;
  x:=TStreamAdapter.Create(
    TFileStream.Create('test.bin',fmOpenRead),soOwned);
  (d as IPersistStream).Load(x);
  x:=nil;

效果很好。 (但再次失败,没有x:=nil;)所以不用担心d, it is a IPersistStream并且行为正确。为什么需要明确nil分配以强制_Release称呼?这是 Delphi 7 的已知问题吗?是因为链接器/编译器开关吗?


这是声明IPersistStream.Save:

function Save(const stm: IStream; fClearDirty: BOOL): HResult; stdcall;

关键点是流参数传递为const。这意味着Save函数不引用IStream界面。它的引用计数既不增加也不减少。由于这两种情况都没有发生,因此它永远不会被破坏。

解决这个问题的方法是确保某些东西拥有对接口的引用。这就是您在第二个示例中演示的内容。

您需要分配任务的原因nil取决于此代码的执行顺序:

x := TStreamAdapter.Create(
  TFileStream.Create('test.bin',fmOpenRead),soOwned
);

它按以下顺序发生:

  1. TFileStream.Create.
  2. TStreamAdapter.Create.
  3. x._Release清除旧的参考。
  4. 参考一下新的IStream.

这显然是错误的顺序。你需要清除x打电话之前TFileStream.Create.


根据前 Embarcadero 编译器工程师 Barry Kelly 的说法,关于传递给 const 参数的接口的问题是一个错误。它从未被修复,我个人已经放弃了这种情况发生的希望。

我的 SSCCE 演示该问题的位置如下:

program SO22846335;

{$APPTYPE CONSOLE}

type
  TMyInterfaceObject = class(TObject, IInterface)
    FRefCount: Integer;
    FName: string;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    constructor Create(const Name: string);
    destructor Destroy; override;
  end;

constructor TMyInterfaceObject.Create(const Name: string);
begin
  inherited Create;
  FName := Name;
  Writeln(FName + ' created');
end;

destructor TMyInterfaceObject.Destroy;
begin
  Writeln(FName + ' destroyed');
  inherited;
end;

function TMyInterfaceObject.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  Result := E_NOINTERFACE;
end;

function TMyInterfaceObject._AddRef: Integer;
begin
  Writeln(FName + ' _AddRef');
  Result := AtomicIncrement(FRefCount);
end;

function TMyInterfaceObject._Release: Integer;
begin
  Writeln(FName + ' _Release');
  Result := AtomicDecrement(FRefCount);
  if Result = 0 then
    Destroy;
end;

procedure Foo(const Intf: IInterface);
begin
  Writeln('Foo');
end;

procedure Bar(Intf: IInterface);
begin
  Writeln('Bar');
end;

begin
  Foo(TMyInterfaceObject.Create('Instance1'));
  Bar(TMyInterfaceObject.Create('Instance2'));
  Readln;
end.

Output



Instance1 created
Foo
Instance2 created
Instance2 _AddRef
Bar
Instance2 _Release
Instance2 destroyed
  
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么这个TStreamAdapter没有被释放? 的相关文章

随机推荐

  • 获取Singleton类实例多线程

    要获取具有单例模式的类的实例 我想使用以下函数 这是一个草图 interface uses SyncObjs type TMCriticalSection class TCriticalSection private Dummy array
  • Angular 2 observable-subscribe 显示未定义

    我面临着与 SO 帖子中相同的挑战here尽管在我的服务中我有数据 但我的 component ts 中的订阅方法未定义 请参阅下面的代码 p 组件 ts private getPayItems void console log In ge
  • Git:“git 克隆”到现有文件夹的最佳实践是什么?

    我有该项目的工作副本 没有任何源代码控制元数据 现在 我想在该文件夹中执行相当于 git clone 的操作 并保留本地更改 git clone 不允许我克隆到现有文件夹中 这里的最佳实践是什么 这可以通过克隆到新目录 然后移动 git目录
  • 更改会话中的 tempdir() (更新 R_TempDir)

    我正在寻找一种方法来改变tempdir R 会话开始后的位置 我认为需要更新C级全局变量R TempDir 从 R 内部完成此操作的好方法是什么 更新 西蒙 厄本内克斯unix 工具包有一个函数可以完成这个任务 代码如下 以供将来参考 se
  • Spring Boot 提供被安全阻止的静态内容

    我启动了 Spring Boot Angular 应用程序 现在我想将整个应用程序部署为 jar 所以我创建了 Maven 配置 其中构建了 Angular 应用程序 然后将其复制到 target classes resources 但每个
  • 最小成本的动态规划问题[关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我有一个手机信号塔问题 有n个城镇 我们想在一些城镇建造手机信号塔 每个蜂窝塔都可以覆盖自己及其邻居 每个城镇都有建造手机信号塔的费用 我们想找出建造覆盖所有城镇的手机信号塔的最低成
  • 如何在 Hyperledger Composer 查询中显示交易输入数据

    我正在尝试构建一个历史查询 它允许我查看交易 及其原始输入 我正在尝试基于这个问题的想法https github com hyperledger composer issues 1850 但这已在 Composer Playground 中
  • A a() 是什么意思? [复制]

    这个问题在这里已经有答案了 考虑这段代码 include
  • 角度材质对话框显示两次

    我使用 Leaflet 绘制地图 并尝试使用 Angular Material 来显示一些模态 但遇到了问题 模态 ModalComponent 应该在用户单击地图时打开 我为此添加了单击事件 请参阅MapComponent 在这个事件中
  • 将py文件转换为exe,找不到现有的PyQt5插件目录

    我对 phyton 很陌生 刚刚完成了我的第一个应用程序 现在 我正在尝试将我的 py 文件编译为似乎不起作用的 exe 购买 我到处寻找解决我问题的方法 但似乎找不到 当我运行此命令时 pyinstaller gui py 显示此错误 4
  • MPMediaItem - MPMediaItemArtwork 的 NSCoding 问题

    因此 MPMediaItem 符合 NSCoding 但它包含一个指向 MPMediaItemArtwork 的指针 该指针不符合 NSCoding 因此 如果我尝试存档 MPMediaItem 如果该项目中有一些艺术品 则它将无法取消存档
  • 如何在C#中调用C++ DLL

    我用 dev C 编写了一个 DLL 该DLL的名称是 DllMain dll 它包含两个函数 HelloWorld and ShowMe 头文件如下所示 DLLIMPORT void HelloWorld DLLIMPORT void S
  • Javascript 对象打印为对象对象

    我对节点和 mongo db 都非常陌生 我正在创建从节点到 Mongo 的连接并尝试 CRUD 操作 我的操作在 Operations js 中定义 并且我从索引调用函数 我面临的问题是当我打印回调参数时 coll find toarra
  • NumPy 数学函数比 Python 更快吗?

    我有一个由基本数学函数 abs cosh sinh exp 组合定义的函数 我想知道使用它是否会产生影响 速度 例如 numpy abs 代替abs 以下是计时结果 lebigot weinberg python m timeit abs
  • pdfmake 中未显示页脚

    我有以下代码 可在单击 pdf 时生成数据表 pdf 在自定义功能中 我有一个页脚代码 应该显示页码 document ready function SHOW EXSITING LINE ITEMS var id Model Order I
  • 如何将 Visual Studio 项目作为安装程序发布/部署

    我刚刚为一家公司开发了一个系统 它将用于 50 多台 PC 剩下的唯一问题是安装过程 我认为手动复制项目的整个文件夹效率不高 例如在 Documents 文件夹中 并在每台 PC 上创建 exe 文件的桌面快捷方式 如果可以的话我想压缩一下
  • 使用 C++20 中派生的“使用”CRTP

    我正在尝试了解 CRTP 和 C 20 基本上 我想要拥有可以访问派生类型的静态继承typedefs and using template
  • 有什么方法可以“提交” Redux 中的状态以释放内存吗?

    我正在尝试实时多人游戏我在服务器和客户端上都使用 Redux 来存储应用程序的状态 但是 由于我的游戏是实时的 因此发送到商店的操作量明显高于通常的应用程序 我怀疑这就是 Redux 使用大量内存的原因 据我了解 Redux 将所有分派到内
  • Referrer 策略隐藏自签名证书的 Referrer

    我似乎无法通过自签名证书向开发服务器发出第 3 方 XHR 请求的引荐来源网址 在遵守 Chrome 使用 SAN 而不是 CN 并注册我的自签名本地主机证书后 我在开发工具安全面板中获得了此请求的绿点 但我还得到了以下信息 This re
  • 为什么这个TStreamAdapter没有被释放?

    比较这两个片段 d as IPersistStream Save TStreamAdapter Create TFileStream Create test bin fmCreate soOwned true d as IPersistSt