我写了一个类。这个类包含一个 TObjectList
这个 TObjectList 包含了一组对象的集合类只有些简单的功能、添加、清空等。
清空时我的代码如下:
procedure TColorCodeTable.Clear;
var i:Longint;
begin
  for i := 0 to m_List.Count -1 do
  begin
     m_List.Items[i].Free;
  end;  m_List.Clear;
end;我的思路是:先 Free 所有对象 再把 m_List 中所有无效的对象引用清空。
但程序执行到 m_List.Clear; 时出错。是一个读写无效内存的错误。
跟踪代码发现:执行循环之后这个 List 就无效了。反复检查代码没有发现任何错误。
不解。各位大侠
是哪里出错了。附:增加过程的代码
procedure TColorCodeTable.Add(Obj: TColorCode);
begin
  m_List.Add(Obj);
end;

解决方案 »

  1.   

    使用容器之类的冬冬 请用Create等函数为其分配内存空间。
      

  2.   

    楼主:TObjectList 是比较特殊的
    当 Object 从队列中移出时,Object 就释放了;
    你上面的代码有很多问题!你想释放某一个Object的时候,只需:m_List.Delete[i];
    全部释放:m_List.Clear;
      

  3.   

    procedure TColorCodeTable.Clear;
    var i:Longint;
    begin
      m_List.OwnsObjects:=false;
      for i := 0 to m_List.Count -1 do
      begin
         m_List.Items[i].Free;
      end;  m_List.Clear;
    end;
    其实m_List.OwnsObjects:=True
        m_List.Clear;
    就可以实现自动free
      

  4.   

    procedure TColorCodeTable.Clear;
    var i:Longint;
    begin
      for i := 0 to m_List.Count -1 do
      begin
         m_List.Items[i].Free; // 队列中的对象已经释放,但是还保存着对象指针
      end;  m_List.Clear; // 队列中的对象已经释放,所以这里肯定出错!
    end;
      

  5.   

    清除代码,你倒着来写,一步一删除。这样你试试看?procedure TColorCodeTable.Clear;
    var 
      i:Longint;
    begin
      for i := m_List.Count - 1 downto 0 do
      begin
        m_List.Items[i].Free;
        m_List.Delete(i);
      end;
    end;
      

  6.   

    哦,我看了一下代码,只要删除就可以了。procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
    begin
      if OwnsObjects then
        if Action = lnDeleted then
          TObject(Ptr).Free;
      inherited Notify(Ptr, Action);
    end;在接到删除lnDeleted这个Action之后,就会Free掉。所以你逐个将Object都Free之后,再Clear就有问题了。也就是说,如上面一位仁兄所讲。如果不设置OwnsObjects只Delete就够了。因为默认的OwnsObjects为True。constructor TObjectList.Create;
    begin
      inherited Create;
      FOwnsObjects := True;
    end;
    procedure TColorCodeTable.Clear;
    var 
      i:Longint;
    begin
      for i := m_List.Count - 1 downto 0 do
      begin
        m_List.Delete(i);
      end;
    end;
      

  7.   

    to budded and  zjqyb 兄我认为全部删除不能用Clear,这里的Clear用的是TList.Clearprocedure TList.Clear;
    begin
      SetCount(0);
      SetCapacity(0);
    end;procedure TList.SetCapacity(NewCapacity: Integer);
    begin
      if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
        Error(@SListCapacityError, NewCapacity);
      if NewCapacity <> FCapacity then
      begin
        ReallocMem(FList, NewCapacity * SizeOf(Pointer));
        FCapacity := NewCapacity;
      end;
    end;procedure TList.SetCount(NewCount: Integer);
    var
      I: Integer;
    begin
      if (NewCount < 0) or (NewCount > MaxListSize) then
        Error(@SListCountError, NewCount);
      if NewCount > FCapacity then
        SetCapacity(NewCount);
      if NewCount > FCount then
        FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(Pointer), 0)
      else
        for I := FCount - 1 downto NewCount do
          Delete(I);
      FCount := NewCount;
    end;所以说Clear,仅仅是把容量数量设为0,没有触动Notify,并发送lnDelete去释放每一个Item。所以还得遍历删除一遍。
      

  8.   

    m_List.Items[i].Free;
    错了 如果你的item对应相应的对象的指针,应该这样调用Objecttype(M_List.Items[i]).Destroy;这样才能保证对象正确的释放 要不他指的另一个地址或者地址错误  如果幸运你会释放 但大多数都不会幸运  运行时错误是必然的
      

  9.   

    嘿嘿,为自己脸红,换马甲回答。没有看到倒数第二行,    for I := FCount - 1 downto NewCount do
          Delete(I);是我的失误。就用Clear来清空。可以结贴了。
      

  10.   

    如果 单纯的采用free  可以使用TObject(M_List.Items[i]).Free  会产生内存泄露  因为子类部分的资源没有被释放,也就是说TObject的内存释放了 他的子类的额外内存根本就没释放。  所以应该采用先判断名字类型,然后调用相应的类名进行释放。
      

  11.   

    to ttch 不懂请不要乱讲,谢谢合作。
      

  12.   

    TO ttch对于你的回答,我笑笑。还对应类名释放,子类额外内存…… 你一厢情愿的以为罢了,看来你从来都没有用过调试窗口。
      

  13.   

    to budded and zjqyb 兄不能用Clear是我的失误,清空列表调用Clear就足够了。唉…… 最关键的一行代码没有看到……
      

  14.   

    to ttch多态的意思就是,子类的函数指针可以赋值给父类,换句话说调用父类的虚函数同时也调用了子类的虚函数。调用了TObject.Free,子类的所有Destroy全部都会调用。另外,你所谓的子类内存漏洞…… 唉,请看看Cpu窗口或者Stack call窗口……唉……
      

  15.   

    明白了。
    是这个
    procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
    begin
      if OwnsObjects then
        if Action = lnDeleted then
          TObject(Ptr).Free;
      inherited Notify(Ptr, Action);
    end;OwnsObjects 默认为 true 的。
    释放是可以让它给我完成多谢各位