返回TList时出现Delphi错误 [英] Delphi error while returning TList

查看:74
本文介绍了返回TList时出现Delphi错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了一个非常简单的应用程序,但是我确实无法理解一个问题。看下面的基本代码:

I have made a very simple application but I have an issue that I really cannot understand. Look at this basic code:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, generics.collections, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    test: TList<integer>;
    aList: TList<integer>;
  public
    { Public declarations }
    function testGenerics: TList<integer>;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 test := testGenerics;
 test.Sort;
 showmessage(test[0].tostring);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 test := TList<integer>.Create;
 aList := TList<integer>.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 aList.Free;
 test.Free;
end;

function TForm1.testGenerics: TList<integer>;
begin

  aList.Add(4);
  result := aList;

end;

end.

基本上,当表单打开时,我将创建 test aList ,然后当我按下按钮时,调用函数 testGenerics 。为什么出现无效的指针操作错误?

Basically when the Form opens I am going to create test and aList and then when I press the button the function testGenerics is called. Why do I have the Invalid pointer operation error?

我真的无法理解,因为我正在正确地创建和销毁对象(我想)。相反,此代码可以正常工作:

I really cannot understand since I am creating and destroying the objects (I guess) properly. This code instead works fine:

function TForm1.testGenerics: TList<integer>;
begin

  Result := TList<integer>.Create;
  Result.Add(4);

end;

在这种情况下,我将返回 TList< integer>的实例,但在上述情况下,我还返回了 aList (这是一个TList)的实例。

In this case I am returning an instance of TList<integer> but also in the case above I am returning an instance of aList (which is a TList).

如果我在第一种情况下是正确的 test:= testGenerics 就像 test := aList (因为我实际上返回的是aList),所以我要给 test aList相同的引用。我对么?

If I'm correct in the first case test := testGenerics is like test := aList (because I am returning aList in fact) so I am going to give test the same reference as aList. Am I correct?

推荐答案

在第一个示例中,每当调用 testGenerics()时,您正在重新分配 test 指向 aList 对象。您将丢失在 OnCreate 事件中创建的原始 test 对象的跟踪,因此该对象已泄漏。然后在 OnDestroy 事件中,当您调用 test.Free 时,它会崩溃,因为您已经释放了 aList 对象,因此您尝试第二次释放同一对象,这是无效操作。

In the first example, whenever you call testGenerics(), you are re-assigning test to point at the aList object. You are losing track of the original test object created in the OnCreate event, so it is leaked. And then in the OnDestroy event, when you call test.Free, it crashes because you already freed the aList object beforehand, so you are trying to free the same object a second time, which is an invalid operation.

第二个示例,您仍然在泄漏原始的 test 对象(以及分配并分配给<$ c $的每个 TList c> test ,最后一个除外),但是您没有重新分配 test 指向 aList 对象,因此 OnDestroy 事件不会崩溃,因为两个变量都指向单独的对象。

In the second example, you are still leaking the original test object (and every TList you allocate and assign to test, except for the last one), but you are not re-assigning test to point at the aList object anymore, so there is no crash in the OnDestroy event because both variables are pointing at separate objects.

您首先要完成什么?以这种方式返回对象不是一个好习惯。在1个元素的列表上调用 Sort()也没有任何意义。

What are you trying to accomplish in the first place? Returning objects in this manner is not good practice. Nor does it make sense to call Sort() on 1-element lists.

如果您要填充 test 随着时间的推移具有多个值,您应该将 test 作为输入参数传递给 testGenerics( )(或者只是让 testGenerics()直接通过 test > Self ),完全不要使用返回值。

If you are trying to populate test with multiple values over time, you should pass test as an input parameter to testGenerics() (or just let testGenerics() access test directly via Self), don't use the return value at all.

在任何情况下,都请摆脱 aList 私有成员,因为您无论如何都不会对其进行任何操作。

And in any case, get rid of your aList private member, as you are not doing anything with it anyway.

尝试一下:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, generics.collections, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    test: TList<integer>;
  public
    { Public declarations }
    procedure testGenerics(aList: TList<integer>);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  testGenerics(test);
  test.Sort;
  ShowMessage(test[0].tostring);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  test := TList<integer>.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  test.Free;
end;

procedure TForm1.testGenerics(aList: TList<integer>);
begin
  // FYI, a better way to exercise Sort()
  // would be to use RandomRange() instead
  // of a hard-coded number...
  aList.Add(4);
end;

end.

这篇关于返回TList时出现Delphi错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆