REA*_*OFO -1 delphi memory-leaks class tstringlist
我有这些代码
TSql = class
private
FConnString: TStringList;
public
property ConnString: TStringList read FConnString write FConnString;
constructor Create;
destructor Destroy;
end;
var
Sql: TSql;
...
implementation
{$R *.dfm}
constructor TSql.Create;
begin
//inherited Create;
FConnString:=TStringList.Create;
end;
destructor TSql.Destroy;
begin
FConnString.Free;
//inherited Destroy;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Sql.Create;
Sql.ConnString.Add('something');
showmessage(Sql.ConnString.Text);
Sql.Destroy;
end;
Run Code Online (Sandbox Code Playgroud)
在按下按钮后,为什么在创建FConnString时会产生内存泄漏?
.................................. ................ .................. ................................ .. ..................................
All*_*uer 11
我看到有两件事.关于析构函数缺少"覆盖"的其他评论和答案已经涵盖了第一个.
第二个问题是财产申报本身.通常,您不应声明引用"write"子句中的对象字段的属性.原因是分配给该属性将"泄漏"该字段中的现有实例.使用属性声明的"write"子句的方法:
property ConnString: TStringList read FConnString write SetConnString;
...
procedure TSql.SetConnString(Value: TStringList);
begin
FConnString.Assign(Value);
end;
Run Code Online (Sandbox Code Playgroud)
另请注意,此方法也不会覆盖FConnString字段.它只是将Value TStringList的"value"或"content"复制到FConnString实例中.通过这种方式,TSql实例可以完全控制该字段的生命周期.分配该属性的代码负责控制Value TStringlist的生命周期.
问题中的原始代码如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
Sql.Create;
Sql.ConnString.Add('something');
showmessage(Sql.ConnString.Text);
Sql.Destroy;
end;
Run Code Online (Sandbox Code Playgroud)
问题路Sql.Create;应该是什么Sql := TSql.Create;.导致内存泄漏的原因如下:
Sql.Create;从零引用中调用.TStringList.Create;并尝试将结果分配给FConnString.TStringList创建的实例.你的析构函数是虚拟的,你不会压倒一切.
你不是在调用你继承的析构函数.
TSql = class
private
FConnString: TStringList;
public
property ConnString: TStringList read FConnString write FConnString;
constructor Create;
destructor Destroy; override; //Correction #1
end;
destructor TSql.Destroy;
begin
FConnString.Free;
inherited Destroy; //Correction #2
end;
Run Code Online (Sandbox Code Playgroud)
一些一般提示:
我赞赏你使用组合(制作FConnString成员而不是继承TStringList).但是,通过公开展示它,您将失去许多好处.具体而言,您将接触到Demeter违规法.我不是说永远不要这样做.但请注意,如果大量客户端代码ConnString直接访问,您可以在线下创建维护问题.
声明FConnString: TStringList;违反了Program对接口的原则,而不是实现.TStringList是一个特定的实现,TStrings并且此声明阻止使用其他子类TStrings.与#1相比,这更是一个问题:如果在几年内你发现并想要切换到不同/更好的子类实现的TStrings客户端代码TStringList现在绑定到现在会产生更多的工作和风险.基本上,首选的方法可以概括为:
这是一般指导原则.如果您特别需要访问TStringList在层次结构级别添加的属性/方法,则必须绑定到该类.但如果你不需要它,不要这样做.
| 归档时间: |
|
| 查看次数: |
1452 次 |
| 最近记录: |