【问题标题】:Error in Free TStringList Object空闲 TStringList 对象中的错误
【发布时间】:2009-09-08 13:43:08
【问题描述】:
procedure FreeListObjects( l : TStrings);
var i : integer;
BEGIN
   FOR i :=  0 TO l.Count -1 DO BEGIN
       l.Objects[i].Free;
       l.Objects[i] := NIL;
   END;
end;



PROCEDURE StringListAdd;
VAR i : INTEGER; Code : LONGWORD;
BEGIN
   l := Classes.TstringLIST.CREATE;
   FOR i := 0 TO 4 DO BEGIN
       Code := i  ;
       l.AddObject('', TObject(code));
   END;
   Code := LONGWORD(l.Objects[2]);
   FreeListObjects(l);
   l.Free;
END;

当我使用l.OwnsObjects := TRUE 没有 FreeListObjects(l) 时,会发生错误。

谁来释放这个字符串列表的对象?

【问题讨论】:

  • Mounir...你有什么问题?
  • 你有什么错误信息?
  • 你知道,当一个全新的、不习惯我们的风格和惯例的人出现并提出一个问题并且它的格式不够正确或描述性不够时,我们应该欢迎他们并帮助他们找到一个答案,而不是联合起来反对他们,让他们淹没在反对票和关闭请求中。你们真丢脸。
  • @Mason - 我不同意;人们正在向 OP 询问更多信息。如果提供了该信息,通常会很快看到问题重新打开。正确回答一个不完整的问题非常困难。
  • @Marc:我没有看到任何不完整的问题。我打开 Delphi,将他的代码粘贴进去,添加对 StringListAdd 的调用,点击 Run,然后立即出现异常。正如他最后几行所暗示的那样,问题在于释放对象。这里没有不完整的信息;只是人们联合起来对付一个问题措辞非常糟糕的新手,这对 StackOverflow 以及特别是关于 SO 的 Delphi 社区产生了相当负面的印象。

标签: delphi tstringlist


【解决方案1】:

您已经告诉字符串列表它拥有Objects 数组中的对象。在这种情况下,它会在您销毁列表时自动对所有这些值调用 Free,就像您的 FreeListObjects 代码一样。

但那里没有对象!您已获取Integer 值,它们不是对象,并将它们强制转换为TObject。您不能在Integer 上调用Free,但是在任何代码调用Free 时,它都不知道值的原始类型。当您进行类型转换时,您告诉编译器您知道自己在做什么,并且编译器相信您。如果您真的不知道自己在做什么,请不要进行类型转换。

你说没有FreeListObjects 会出错,但你应该得到错误 FreeListObjects。问题是您在不是对象的东西上调用Free。无论您是在自己的代码中调用它还是让库调用它都无关紧要。

您可能已经花了一些时间使用 C#。在那种语言中,整数会自动“装箱”成为真实的对象。这不是 Win32 Delphi 的工作方式。 Delphi 不做装箱和拆箱。

【讨论】:

    【解决方案2】:

    OwnsObjects 与您的 FreeObjects 例程基本相同,但它会在 StringList 本身被释放时在内部进行处理。

    但在我看来,您的问题来自您的示例。当我运行它时,我会遇到访问冲突,因为您保存的“对象”根本不是对象,它们是您强制到 TObject 插槽的整数。

    这只是一个猜测,但你只是在学习 Delphi,在“一切都是对象”的其他语言背景之后?在德尔福中并非如此。对象是众多数据类型中的一种,您不能对其他数据类型调用 Free。

    【讨论】:

      【解决方案3】:

      问题在于,当您设置 OwnObjects := true 时,列表将免费调用其中的每个项目。但是,由于您只是将整数转换为 TObject,并没有真正创建 Integer 类型的对象,因此您无法调用此转换对象中的任何方法。

      解决您的问题的方法是创建一个这样的类:

      TInteger = class
        value: integer;
        constructor Create(v: integer);
      end;
      

      并在您的列表项中放入此类的实例,替换:

         l.AddObject('', TObject(code));
      

         l.AddObject('', TInteger.Create(code));
      

      【讨论】:

        【解决方案4】:

        扩展 Rob 的回答:您试图释放与地址相关的东西:nil、0x00000001、0x00000002、0x00000003 和 0x00000004。由于那里没有有效的对象,所以会出现访问冲突(注意:对 nil 对象调用 Free 不会产生错误)。

        【讨论】:

        • 这是对错误的最佳解释。当您将对象添加到对象列表时,它们确实需要是对象。在 WIN32 中,整数不是对象! (对于没有 WIN32 经验的 .NET 开发人员的常见错误。)在 Delphi for .NET 中,此代码可能确实有效!
        【解决方案5】:

        其他人已经在您的代码中指出了问题,所以我只添加一个小信息。如果您只想将整数存储在列表中,请使用我的GpLists 单元中的 TGpIntegerList 或 TGpInt64List。免费,无附加条件。

        【讨论】:

          【解决方案6】:

          对不起,这是我第一次在 stackoverflow 中,下次我的问题会更准确。 我认为 l.addobject 将在 tstringlist 中创建和添加对象。 l.addobject('', tobject(code)) (其中 l 是 tstringlist 并且 code 是 longword) 是否造成内存泄漏? longword 什么时候定位? 我总能得到代码 := Longword(L.objects[i]); 我正在输入什么对象?

          【讨论】:

          • 你的问题中唯一的问题是它没有提到它是什么语言。欢迎来到 Stack Overflow。投票给你的四个(!)人反应严重。无论如何,正如已经解释过的,没有对象。你没有分配任何内存,所以没有什么可以泄漏的。 AddObject 的文档是否会分配一个新对象?该列表存储您给它的值的副本。在您的情况下,该值是一个整数,尽管它 预计 该值是一个对象引用。 (请注意,复制对象引用不会复制对象。)
          【解决方案7】:

          我知道在 Delphi 中,您需要通过执行以下操作来释放每个对象。

          例如,如果您的对象属于以下类别。

          TheClass = Class(TObject)
          public
          thestr:String;
          end;
          

          那么你会这样做:

          procedure FreeListObjects( l : TStrings);
          var i : integer;
          BEGIN
             FOR i :=  0 TO l.Count -1 DO BEGIN
                 TheClass(l.Objects[i]).Free;   <----
                 l.Objects[i] := NIL;
             END;
          end;
          

          TStrings 列表中的每个对象实际上都驻留在它们自己的内存位置,即使您正在释放指向对象的指针。您需要通过执行上述操作来释放对象内存。我就是这样做的,并且在 Delphi 中做到了。它一直对我有用。

          【讨论】:

          • 强制转换为 TheClass 只是为了调用 Free 是不必要的 - 所有的析构函数通常都会在继承树上到达 TObject,如果它们不这样做,应用程序无论如何都会遇到麻烦
          猜你喜欢
          • 2015-07-11
          • 2013-12-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-22
          • 2016-06-17
          相关资源
          最近更新 更多