代码之家  ›  专栏  ›  技术社区  ›  user1580348

TJClstringlist免费崩溃

  •  2
  • user1580348  · 技术社区  · 5 年前

    创建一个简单的VCL应用程序:

    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
    
    type
      TForm1 = class(TForm)
       procedure FormDestroy(Sender: TObject);
       procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    uses
      JclStringLists;
    
    var
      MyList1: TJclStringList;
      MyList2: TJclStringList;
    
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      MyList1.Free;
      MyList2.Free;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      MyList1 := TJclStringList.Create;
      MyList2 := TJclStringList.Create;
      MyList1.LoadFromFile('C:\ONE.txt');
      MyList2.LoadFromFile('C:\TWO.txt');
      Self.Caption := Self.Caption + ' ' + IntToStr(MyList1.Count);
      Self.Caption := Self.Caption + ' ' + IntToStr(MyList2.Count);
    end;
    
    end.
    

    它崩溃在 TForm1.FormDestroy 尝试释放时的事件处理程序 MyList1 对象实例。为什么?

    1 回复  |  直到 5 年前
        1
  •  6
  •   David Heffernan    5 年前

    TJclStringList 是引用计数类型(在 JCLStringLists.pas 作为 type TJclStringList = class(TJclInterfacedStringList, IInterface, IJclStringList) 实现了这两个目标 _AddRef _Release 为了处理引用计数),所以您根本不应该将它们创建为对象,也不应该手动释放它们-当对它们的引用超出范围时,它们将自动释放。(这也意味着您不应该将它们声明为全局变量,因为这样您就不会在它们的生命周期中保持控制权。)

    这个 JclStringLists 单元提供了几个函数,可以为您正确地创建接口的实例。你可以在那个单元看到它们,就在 implementation 关键词:

    function JclStringList: IJclStringList; overload;
    function JclStringListStrings(AStrings: TStrings): IJclStringList; overload;
    function JclStringListStrings(const A: array of string): IJclStringList; overload;
    function JclStringList(const A: array of const): IJclStringList; overload;
    function JclStringList(const AText: string): IJclStringList; overload;
    

    正确的使用方法 TJC表 做你想做的事情是这样的:

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, JCLStringLists;
    
    type
      TForm1 = class(TForm)
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        { Private declarations }
        MyList1, MyList2: IJCLStringList;  // Note I and not T in type.
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      MyList1 := JclStringList;
      MyList1.LoadFromFile('C:\Work\Data\FirstName.txt');
      MyList2 := JclStringList
      MyList2.LoadFromFile('C:\Work\Data\LastName.txt');
    
      // Only to demonstrate that both files got loaded by the code above.
      Self.Caption := Format('First: %d Last: %d', [MyList1.Count, MyList2.Count]);
    end;
    
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      // Do NOT free the JclStringLists here - they will automatically be released when
      // the form is destroyed because the reference count will reach zero (as long as
      // you don't have any other references to those variables, which by putting them into
      // the private section is unlikely.
    end;
    
    end.