快速放分,释放变量的问题

Rail100 2006-05-31 10:28:21
一个ListView放在一个Panel里,例如
ListView1 := TListView.Create(nil);
Panel1 := TPanel.Create(nil);
Panel1.Parent := Form1;
ListView1.Parent := Panel1;


在释放的时候,如果:
ListView1.Free;
Panel1.Free;
这样不出错

如果
Panel1.Free;
ListView1.Free;//这里会提示内存释放出错。

请高手解答一下释放的机制?是否Parent在释放的时候会释放子控件的内存?
...全文
201 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
yyjzsl 2006-06-01
  • 打赏
  • 举报
回复
路过了,顶下
shaoyan 2006-06-01
  • 打赏
  • 举报
回复
肯定是先 free子类才行
Rail100 2006-06-01
  • 打赏
  • 举报
回复
谢谢大家
^_^
hellolongbin 2006-06-01
  • 打赏
  • 举报
回复
看刘艺的《delphi面向对象编程思想》,里面有详细的解释
ysai 2006-06-01
  • 打赏
  • 举报
回复
>>好像也并没有判断对象是否还存在
不用判断,控件释放时会自动移除它在父控件及拥有者的集合的引用,如
destructor TControl.Destroy;
begin
Application.ControlDestroyed(Self);
if (FHostDockSite <> nil) and not (csDestroying in FHostDockSite.ComponentState) then
begin
FHostDockSite.Perform(CM_UNDOCKCLIENT, 0, Integer(Self));
SetParent(nil);//<<==这里
Dock(NullDockSite, BoundsRect);
FHostDockSite := nil;
end else
SetParent(nil);//<<==这里
FActionLink.Free;
FActionLink := nil;
FConstraints.Free;
FFont.Free;
StrDispose(FText);
inherited Destroy;
end;

destructor TComponent.Destroy;
begin
Destroying;
if FFreeNotifies <> nil then
begin
while Assigned(FFreeNotifies) and (FFreeNotifies.Count > 0) do
TComponent(FFreeNotifies[FFreeNotifies.Count - 1]).Notification(Self, opRemove);
FreeAndNil(FFreeNotifies);
end;
DestroyComponents;
if FOwner <> nil then FOwner.RemoveComponent(Self);//<<==这里
inherited Destroy;
end;
深宇 2006-06-01
  • 打赏
  • 举报
回复
呵呵,找到原因了
destructor TWinControl.Destroy;
var
I: Integer;
Instance: TControl;
begin
Destroying;
if FDockSite then
begin
FDockSite := False;
RegisterDockSite(Self, False);
end;
FDockManager := nil;
FDockClients.Free;
if Parent <> nil then RemoveFocus(True);
if FHandle <> 0 then DestroyWindowHandle;
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
FBrush.Free;
{$IFDEF LINUX}
if FObjectInstance <> nil then WinUtils.FreeObjectInstance(FObjectInstance);
{$ENDIF}
{$IFDEF MSWINDOWS}
if FObjectInstance <> nil then Classes.FreeObjectInstance(FObjectInstance);
{$ENDIF}
FPadding.Free;
inherited Destroy;
end;

关键是这个函数解决了冲突问题
Remove(Instance);

procedure TWinControl.Remove(AControl: TControl);
begin
if AControl is TWinControl then
begin
ListRemove(FTabList, AControl);
ListRemove(FWinControls, AControl);
end else
ListRemove(FControls, AControl);
AControl.FParent := nil;
end;

procedure ListRemove(var List: TList; Item: Pointer);
begin
List.Remove(Item);
if List.Count = 0 then
begin
List.Free;
List := nil;
end;
end;

这两个函数移除了componentlist中对应的项,这样释放owner的释放机制就不会重复释放了
由此可见,delphi是先释放parent的,然后才释放owner的
深宇 2006-06-01
  • 打赏
  • 举报
回复
to ysai(所有真的都是假的真,所有假的都是真的假)
假如既设定了parent,又设定了owner,delphi会如何处理释放的过程呢?

destructor TComponent.Destroy;
begin
Destroying;
if FFreeNotifies <> nil then
begin
while Assigned(FFreeNotifies) and (FFreeNotifies.Count > 0) do
TComponent(FFreeNotifies[FFreeNotifies.Count - 1]).Notification(Self, opRemove);
FreeAndNil(FFreeNotifies);
end;
DestroyComponents;
if FOwner <> nil then FOwner.RemoveComponent(Self);
inherited Destroy;
end;

procedure TComponent.DestroyComponents;
var
Instance: TComponent;
begin
while FComponents <> nil do
begin
Instance := FComponents.Last;
if (csFreeNotification in Instance.FComponentState)
or (FComponentState * [csDesigning, csInline] = [csDesigning, csInline]) then
RemoveComponent(Instance)
else
Remove(Instance);
Instance.Destroy;
end;
end;

function TList.Last: Pointer;
begin
Result := Get(FCount - 1);
end;

function TList.Get(Index: Integer): Pointer;
begin
if (Index < 0) or (Index >= FCount) then
Error(@SListIndexError, Index);
Result := FList^[Index];
end;

好像也并没有判断对象是否还存在
clasj 2006-06-01
  • 打赏
  • 举报
回复
显然ysai说的最好。
ysai 2006-06-01
  • 打赏
  • 举报
回复
destructor TWinControl.Destroy;
var
I: Integer;
Instance: TControl;
begin
Destroying;
if FDockSite then
begin
FDockSite := False;
RegisterDockSite(Self, False);
end;
FDockManager := nil;
FDockClients.Free;
if Parent <> nil then RemoveFocus(True);
if FHandle <> 0 then DestroyWindowHandle;
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
FBrush.Free;
{$IFDEF LINUX}
if FObjectInstance <> nil then WinUtils.FreeObjectInstance(FObjectInstance);
{$ENDIF}
{$IFDEF MSWINDOWS}
if FObjectInstance <> nil then Classes.FreeObjectInstance(FObjectInstance);
{$ENDIF}
inherited Destroy;
end;



注意这段
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
也就是说,TWinControl会释放Controls集合里的所有对象,即它会释放Parent为它的所有控件.
示例代码:
procedure TForm1.Action1Execute(Sender: TObject);
var
b : TButton;
begin
ShowMessage(IntToStr(Self.ControlCount));
b := TButton.Create(nil);
b.Parent := Self;
ShowMessage(IntToStr(Self.ControlCount));
end;

所以你的Panel1释放会释放掉Panel1里的ListView1,而不管ListView1的Owner是谁
postren 2006-06-01
  • 打赏
  • 举报
回复
都说了,路过一下
andyzhou1101 2006-06-01
  • 打赏
  • 举报
回复
学习
GARNETT2183 2006-06-01
  • 打赏
  • 举报
回复
有没有看到所有组件基本上的Crate函数都有个这样的参数Create(AOwner: TComponent);
如果在创建一组件时,指定了AOwner的话,比如:

var
Panel1: TPanel;
begin
Panel1 := TPanel.Create(From1);
//////////////
这样如果释放Form1的话,Panel1会自己释放...所以在窗口上的组件不用我们手动释放的原因了
如果不指定父组件的话。这个就必须自己释放了...
hellolongbin 2006-06-01
  • 打赏
  • 举报
回复
ListView1.Parent := Panel1;
你先把它爹释放了,皮之不存,毛将焉附?

你用的是create(nil),所以必须手动释放
slatly 2006-06-01
  • 打赏
  • 举报
回复
看不懂 友情路过
老之 2006-05-31
  • 打赏
  • 举报
回复
在创建时是用Create(nil),如果先释放父控件的话,是否它的子控件也被释放了呢?
-----
子控件没有被释放。释放和指向空指针是不同的。
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;//这个就是指向空指针
Temp.Free;//这个是释放
end;

Rail100 2006-05-31
  • 打赏
  • 举报
回复
请问,在创建时是用Create(nil),如果先释放父控件的话,是否它的子控件也被释放了呢?
因为我再释放子控件时明显指向了空指针。

如果是这样的话,Create(nil)和Create(Owner)好像在释放时没不同吧?
老之 2006-05-31
  • 打赏
  • 举报
回复
因为创建时是用Create(nil),对象的拥有者是空,释放时必须先释放子控件(ListView1),再释放父控件(Panel1)。如果创建ListView1时是ListView1 := TListView.Create(Panel1);指定了它的拥有者是Panel1,那么在释放Panel1时,它下面的控件也会自动释放。
cowbosky 2006-05-31
  • 打赏
  • 举报
回复
路过...

顶一下......

5,392

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧