alo*_*ono 11 delphi inheritance generic-collections
为什么这个程序会报告内存泄漏?
{$APPTYPE CONSOLE}
uses
System.Generics.Collections;
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create;
end;
constructor TDerivedGenericObjectList.Create;
begin
inherited;
end;
var
List: TDerivedGenericObjectList;
begin
ReportMemoryLeaksOnShutdown := True;
List := TDerivedGenericObjectList.Create;
List.Add(TObject.Create);
List.Free;
end.
Run Code Online (Sandbox Code Playgroud)
Dav*_*nan 14
你正在调用无参数构造函数TObjectList<T>.这实际上是派生TList<T>的类的构造函数TObjectList<T>.
声明的所有构造函数都TObjectList<T>接受一个名为的参数AOwnsObjects,该参数用于初始化该OwnsObjects属性.因为您绕过该构造函数,OwnsObjects默认为False,并且列表的成员不会被销毁.
您应该确保调用TObjectList<T>该初始化的构造函数OwnsObjects.例如:
{$APPTYPE CONSOLE}
uses
System.Generics.Collections;
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create;
end;
constructor TDerivedGenericObjectList.Create;
begin
inherited Create(True);
end;
var
List: TDerivedGenericObjectList;
begin
ReportMemoryLeaksOnShutdown := True;
List := TDerivedGenericObjectList.Create;
List.Add(TObject.Create);
List.Free;
end.
Run Code Online (Sandbox Code Playgroud)
也许更好的变体是让你的构造函数也提供AOwnsObjects参数:
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create(AOwnsObjects: Boolean = True);
end;
constructor TDerivedGenericObjectList.Create(AOwnsObjects: Boolean);
begin
inherited Create(AOwnsObjects);
end;
Run Code Online (Sandbox Code Playgroud)
要么:
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create(AOwnsObjects: Boolean = True);
end;
constructor TDerivedGenericObjectList.Create(AOwnsObjects: Boolean);
begin
inherited;
end;
Run Code Online (Sandbox Code Playgroud)
所以,您可能想知道为什么原始版本选择了一个TList<T>构造函数而不是一个TObjectList<T>.那么,让我们更详细地看一下.这是你的代码:
type
TDerivedGenericObjectList = class(TObjectList<TObject>)
public
constructor Create;
end;
constructor TDerivedGenericObjectList.Create;
begin
inherited;
end;
Run Code Online (Sandbox Code Playgroud)
当inherited以这种方式使用时,编译器会用完全相同的签名,因为这一个构造函数.它找不到一个,TObjectList<T>因为它们都有参数.它可以找到一个TList<T>,这就是它使用的那个.
正如您在评论中提到的,以下变体不会泄漏:
constructor TDerivedGenericObjectList.Create;
begin
inherited Create;
end;
Run Code Online (Sandbox Code Playgroud)
与裸体相比,此语法inherited将找到在替换默认参数时匹配的方法.因此TObjectList<T>调用单个参数构造函数.
该文档包含以下信息:
继承的保留字在实现多态行为中起着特殊的作用.它可以在方法定义中出现,有或没有标识符.
如果继承后跟成员的名称,则表示正常的方法调用或对属性或字段的引用,除了搜索引用的成员以封闭方法的类的直接祖先开始.例如,在:
Run Code Online (Sandbox Code Playgroud)inherited Create(...);发生在方法的定义中,它调用继承的Create.
当继承后面没有标识符时,它引用与封闭方法同名的继承方法,或者如果封闭方法是消息处理程序,则引用同一消息的继承消息处理程序.在这种情况下,inherited不使用显式参数,而是将与调用封闭方法相同的参数传递给inherited方法.例如:
Run Code Online (Sandbox Code Playgroud)inherited;在构造函数的实现中经常发生.它使用传递给后代的相同参数调用继承的构造函数.