尝试释放FSQL时,Delphi XE3指针无效(TStringList)

时间:2014-07-17 20:45:47

标签: delphi delphi-xe3 object-destruction invalid-pointer

我在XE3中创建了一个新应用,但使用了在D2007中创建的一些单元。

我在释放TStringList数据项时遇到错误。这是创建数据项FSQL的代码:

procedure TPayorDM.DataModuleCreate(Sender: TObject);
begin
  FPayorDRM := TDRM.Create;
  FSQL := TStringList.Create;
end;

这是获取错误的代码:

procedure TPayorDM.DataModuleDestroy(Sender: TObject);
begin
  FreeAndNil(FSQL);
  if T_Payor.Active then T_Payor.Close;
  FreeAndNil(FPayorDRM);
end;

错误发生在' FreeAndNil(FSQL);'。我尝试了FSQL.Free'我得到了相同的结果。

这是我得到的错误:

项目:PayorUpdate.exe引发异常类EInvalidPointer,消息'无效的指针操作。

当我打破蓝色箭头(调试模式)指向_FreeMem(指针(Self));在System单元中的TObject.FreeInstance过程中,如下所示:

procedure TObject.FreeInstance;
begin
  CleanupInstance;
  _FreeMem(Pointer(Self));
end;

如果我没有释放TStringList数据项,我会在应用程序中发生内存泄漏。

是否可能需要设置配置选项?我使用谷歌进行搜索,除了以下三种可能之一外,没有发现任何可以解释我做错的事情:

  • 它是由其他一些内存管理员分配的。
  • 之前已经被释放了一次。
  • 它从未被任何东西分配过。

如果我试一试......除了......我能解决这个问题,但我不想这样做。

BTW,我有另一个TStringList在不同的单位,我创建和FreeAndNil,我没有得到任何错误。

以下是整个来源:


    unit PayorDataMgr;

    interface

    uses
      SysUtils,
      Classes,
      Dialogs,
      NativeXML,
      adscnnct,
      DB,
      adsdata,
      adsfunc,
      adstable,
      ace,
      cbs.drm,
      cbs.utils,
      cbs.LogFiles;

    const
      POLICY_TYPES: array[1..3] of string = ('Primary','Secondary','Tertiary');

    type
      TPayorRecord = Record
        ASSIGNBENEFITS: Boolean;
        AUTHORIZE: Boolean;
        BATCHBILL: Boolean;
        CLAIMMAX: Integer;
        DISCONTINUED: TDateTime;
        DISPENSEUPDATE: Boolean;
        EHRSIGNOFF: Boolean;
        EMCDEST: String;
        FORM: String;
        GOVASSIGN: Boolean;
        HIDE: Boolean;
        IGRPUNIQUE: Integer;
        LEGACYPLAN: String;
        LEGACYTYPE: String;
        LOCALATTN: String;
        LOCALCITY: String;
        LOCALNAME: String;
        LOCALPHONE: String;
        LOCALSTATE: String;
        LOCALSTREET: String;
        LOCALZIP: String;
        MASTERATTN: String;
        MASTERCITY: String;
        MASTERNAME: String;
        MASTERPHONE: String;
        MASTERSTATE: String;
        MASTERSTREET: String;
        MASTERZIP: String;
        MEDIGAPCODE: String;
        MEDIGAPPAYOR: Boolean;
        MEDPLANGUID: String;
        MODIFIED: TDateTime;
        NEICCODE: String;
        NEICTYPESTDC: Integer;
        OWNER: String;
        PAYORGUID: String;
        PAYORSUBTYPESTDC: Integer;
        PAYORTYPESTDC: Integer;
        PAYORUNIQUE: Integer;
        PAYPERCENT: Integer;
        RTCODE: String;
        SRXPLANGUID: String;
        STATEFILTER: String;
        procedure Clear;
      End;

      TPayors = Record
      private
        function _pGetCount: Integer;
      public
        Items: Array of TPayorRecord;
        procedure Add(const aItem:TPayorRecord);
        function CarriersList:TStrings;
        procedure Free;
        function GetPayorGuid(const aPAYORUNIQUE:Integer):String;
        function IndexOfIgrpUnique(Const aIGRPUNIQUE:Integer):Integer;
        function IndexOfPayorUnique(Const aPAYORUNIQUE:Integer):Integer;
        procedure SortByName;
        property Count:Integer Read _pGetCount;
      End;

      TPayorDM = class(TDataModule)
        CommonConnection: TAdsConnection;
        T_Payor: TAdsTable;
        Q_Payor: TAdsQuery;
        procedure DataModuleDestroy(Sender: TObject);
        procedure DataModuleCreate(Sender: TObject);
      private
        FPayorDRM: TDRM;
        FSQL: TStringList;
        function _LoadRecordFromTable:TPayorRecord;
        function _newIDSTRING(const aFormat:String='F'):String;
        { Private declarations }
        procedure _pSetConnectionHandle(const Value: Integer);
        procedure _pSetErrorMessage(const Value: String);
        procedure _psetSQL(const Value: TStringList);

        { Private properties }
        property ErrorMessage:String Write _pSetErrorMessage;
      public
        function AddPayor(var aPAYORRECORD:TPAYORRECORD):Boolean;
        function ExecuteScript(const aTo,aFrom:string):Boolean;
        function FindPayor(const aPAYORGUID:String):Boolean;overload;
        function FindPayor(const aPAYORUNIQUE:Integer):Boolean;overload;
        function GetPayorData:TDRM;
        function GetRecordCount(const aData:String):Integer;
        function LoadCarriers(const aHide:boolean = False):TPayors;
        function LoadPayor:TPayorRecord;
        function OpenTable:Boolean;
        function UpdateFromXML(const aPayorNode:TXMLNode):boolean;
        { Public declarations }
        property ConnectionHandle:Integer Write _pSetConnectionHandle;
        property DynamicPayorFields:TDRM Read FPayorDRM;
        property SQL:TStringList Read FSQL Write _psetSQL;
      end;

    var
      PayorDM: TPayorDM;

    implementation

    {$R *.dfm}

    function TPayorDM.AddPayor(var aPAYORRECORD: TPAYORRECORD): Boolean;
    begin
      Result := False;
      if IsNull(aPAYORRECORD.LOCALNAME) then Exit;
      { Create uniques }

      { Add Record }
      if not T_Payor.Active then
        if not OpenTable  then Exit;
      with T_Payor do
      try
        Insert;
        FieldByName('PAYORGUID').AsString := _newIDSTRING;
        FieldByName('MASTERNAME').AsString := aPAYORRECORD.MASTERNAME;
        FieldByName('MASTERSTREET').AsString := aPAYORRECORD.MASTERSTREET;
        FieldByName('MASTERCITY').AsString := aPAYORRECORD.MASTERCITY;
        FieldByName('MASTERSTATE').AsString := aPAYORRECORD.MASTERSTATE;
        FieldByName('PAYORTYPESTDC').AsInteger := aPAYORRECORD.PAYORTYPESTDC;
        FieldByName('MASTERZIP').AsString := aPAYORRECORD.MASTERZIP;
        FieldByName('MASTERATTN').AsString := aPAYORRECORD.MASTERATTN;
        FieldByName('MASTERPHONE').AsString := aPAYORRECORD.MASTERPHONE;
        FieldByName('NEICCODE').AsString := aPAYORRECORD.NEICCODE;
        FieldByName('RTCODE').AsString := aPAYORRECORD.RTCODE;
        FieldByName('STATEFILTER').AsString := aPAYORRECORD.STATEFILTER;
        FieldByName('NEICTYPESTDC').AsInteger := aPAYORRECORD.NEICTYPESTDC;
        FieldByName('PAYORSUBTYPESTDC').AsInteger := aPAYORRECORD.PAYORSUBTYPESTDC;
        FieldByName('OWNER').AsString := aPAYORRECORD.OWNER;
        FieldByName('HIDE').AsBoolean := aPAYORRECORD.HIDE;
        FieldByName('IGRPUNIQUE').AsInteger := aPAYORRECORD.IGRPUNIQUE;
        FieldByName('FORM').AsString := aPAYORRECORD.FORM;
        FieldByName('GOVASSIGN').AsBoolean := aPAYORRECORD.GOVASSIGN;
        FieldByName('CLAIMMAX').AsInteger := aPAYORRECORD.CLAIMMAX;
        FieldByName('MEDIGAPCODE').AsString := aPAYORRECORD.MEDIGAPCODE;
        FieldByName('EMCDEST').AsString := aPAYORRECORD.EMCDEST;
        FieldByName('ASSIGNBENEFITS').AsBoolean := aPAYORRECORD.ASSIGNBENEFITS;
        FieldByName('BATCHBILL').AsBoolean := aPAYORRECORD.BATCHBILL;
        FieldByName('MEDIGAPPAYOR').AsBoolean := aPAYORRECORD.MEDIGAPPAYOR;
        FieldByName('MEDPLANGUID').AsString := aPAYORRECORD.MEDPLANGUID;
        FieldByName('SRXPLANGUID').AsString := aPAYORRECORD.SRXPLANGUID;
        FieldByName('PAYPERCENT').AsInteger := aPAYORRECORD.PAYPERCENT;
        FieldByName('LOCALNAME').AsString := aPAYORRECORD.LOCALNAME;
        FieldByName('LOCALSTREET').AsString := aPAYORRECORD.LOCALSTREET;
        FieldByName('LOCALCITY').AsString := aPAYORRECORD.LOCALCITY;
        FieldByName('LOCALSTATE').AsString := aPAYORRECORD.LOCALSTATE;
        FieldByName('LOCALZIP').AsString := aPAYORRECORD.LOCALZIP;
        FieldByName('LOCALATTN').AsString := aPAYORRECORD.LOCALATTN;
        FieldByName('LOCALPHONE').AsString := aPAYORRECORD.LOCALPHONE;
        FieldByName('EHRSIGNOFF').AsBoolean := aPAYORRECORD.EHRSIGNOFF;
        FieldByName('DISCONTINUED').AsDateTime := aPAYORRECORD.DISCONTINUED;
        FieldByName('MODIFIED').AsDateTime := Now;
        FieldByName('LEGACYPLAN').AsString := aPAYORRECORD.LEGACYPLAN;
        FieldByName('LEGACYTYPE').AsString := aPAYORRECORD.LEGACYTYPE;
        FieldByName('AUTHORIZE').AsBoolean := aPAYORRECORD.AUTHORIZE;
        FieldByName('DISPENSEUPDATE').AsBoolean := aPAYORRECORD.DISPENSEUPDATE;
        Post;
        aPAYORRECORD.PAYORUNIQUE := FieldByName('PAYORUNIQUE').AsInteger;
        aPAYORRECORD.PAYORGUID := FieldByName('PAYORGUID').AsString;
        Close;
        Result := True;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'AddPayor: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message;
      end;
      end;
    end;

    procedure TPayorDM.DataModuleCreate(Sender: TObject);
    begin
      FPayorDRM := TDRM.Create;
      FSQL := TStringList.Create; { FSQL Created }
   end;

    procedure TPayorDM.DataModuleDestroy(Sender: TObject);
    begin
      try
        FSQL.Free; { FSQL destroyed - work around to get unit to run without error}
      except

      end;
      if T_Payor.Active then T_Payor.Close;
      FreeAndNil(FPayorDRM);
    end;

    function TPayorDM.ExecuteScript(const aTo, aFrom: string):Boolean;
    begin
      Result := False;
      if FSQL.Count = 0 then exit;
      with Q_Payor do
      try
        if Active then Close;
        SQL := FSQL;
        ParamByName('to').Text := aTo;
        ParambyName('from').Text := aFrom;
        ExecSQL;
        if Active then Close;
        Result := True;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'ExecuteScript: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message + ' SQL: ' + Q_Payor.SQL.Text;
      end;
      end;
    end;

    function TPayorDM.FindPayor(const aPAYORUNIQUE: Integer): Boolean;
    begin
      T_Payor.IndexName := 'PAYORUNIQUE';
      Result := T_Payor.FindKey([aPAYORUNIQUE]);
    end;

    function TPayorDM.FindPayor(const aPAYORGUID: String): Boolean;
    begin
      T_Payor.IndexName := 'PAYORGUID';
      Result := T_Payor.FindKey([aPAYORGUID]);
    end;

    function TPayorDM.GetPayorData: TDRM;
    begin
      if FPayorDRM.Count = 0 then
        FPayorDRM.BuildDRMList(T_Payor);
      Result := FPayorDRM;
    end;


    function TPayorDM.GetRecordCount(const aData:string): Integer;
    begin
      Result := 0;
      if FSQL.Count = 0 then exit;
      with Q_Payor do
      try
        if Active then Close;
        SQL := FSQL;
        ParamByName('data').AsString := aData;
        Open;
        Result := RecordCount;
        Close;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'GetRecordCount: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message;
      end;
      end;

    end;

    function TPayorDM.LoadCarriers(const aHide: boolean): TPayors;
    begin
      OpenTable;
      Result.Free;
      with T_Payor do
      begin
        First;
        while not EOF do
        begin
          if T_Payor.FieldByName('HIDE').AsBoolean = aHide then
            Result.Add(_LoadRecordFromTable);
          Next;
        end;
        First;
        Result.SortByName;
      end;
    end;

    function TPayorDM.LoadPayor: TPayorRecord;
    begin
      Result.Clear;
      try
        if not T_Payor.active then exit;
        if T_Payor.RecNo = 0 then exit;
        Result := _LoadRecordFromTable;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'LoadPayor: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message;
      end;
      end;
    end;

    function TPayorDM.OpenTable: Boolean;
    begin
      Result := False;
      with T_Payor do
      try
        if not Active then Open;
        FPayorDRM.BuildDRMList(T_Payor);
        FPayorDRM.LoadValues(T_Payor); { test }
        FPayorDRM.ExportDRMList; { test }
        Result := True;
      except on E: EADSDatabaseError do
      begin
        ErrorMessage := 'OpenTable: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
          ' ERROR: ' + e.Message;
      end;
      end;
    end;

    function TPayorDM.UpdateFromXML(const aPayorNode: TXMLNode): boolean;
    var
      fKeyData:TXMLNode;
      Idx,fPAYORUNIQUE:Integer;
    begin
      Result := False;
      if not Assigned(aPayorNode) then Exit;
      try
        if FPayorDRM.Count = 0 then
          FPayorDRM.BuildDRMList(T_Payor);
        FPayorDRM.ClearValues;
        fKeyData := aPayorNode.FindNode('KeyData');
        FPayorDRM.FindRecordFromKeyData(fKeyData,T_Payor);
        fPAYORUNIQUE := FPayorDRM.FieldByName('PAYORUNIQUE').AsInteger;
        FPayorDRM.LoadValues(aPayorNode);
        if fPAYORUNIQUE = 0 then
        begin
          FPayorDRM.FieldByName('PAYORUNIQUE').AsInteger := 0;
          FPayorDRM.FieldByName('PAYORGUID').AsString := _newIDSTRING;
          FPayorDRM.FieldByName('MODIFIED').AsDate := Now;
          FPayorDRM.AddRecord(T_Payor)
        end
        else
        begin
          FPayorDRM.FieldByName('MODIFIED').AsDate := Now;
          FPayorDRM.UpdateRecord(T_Payor);
        end;
      except on e:exception do
      begin
        ErrorMessage := 'UpdateFromXML: ERROR: ' + e.Message;
      end;
      end;
    end;

    function TPayorDM._LoadRecordFromTable: TPayorRecord;
    begin
      with T_Payor do
      begin
        Result.PAYORUNIQUE := FieldByName('PAYORUNIQUE').AsInteger;
        Result.PAYORGUID := FieldByName('PAYORGUID').AsString;
        Result.MASTERNAME := FieldByName('MASTERNAME').AsString;
        Result.MASTERSTREET := FieldByName('MASTERSTREET').AsString;
        Result.MASTERCITY := FieldByName('MASTERCITY').AsString;
        Result.MASTERSTATE := FieldByName('MASTERSTATE').AsString;
        Result.PAYORTYPESTDC := FieldByName('PAYORTYPESTDC').AsInteger;
        Result.MASTERZIP := FieldByName('MASTERZIP').AsString;
        Result.MASTERATTN := FieldByName('MASTERATTN').AsString;
        Result.MASTERPHONE := FieldByName('MASTERPHONE').AsString;
        Result.NEICCODE := FieldByName('NEICCODE').AsString;
        Result.RTCODE := FieldByName('RTCODE').AsString;
        Result.STATEFILTER := FieldByName('STATEFILTER').AsString;
        Result.NEICTYPESTDC := FieldByName('NEICTYPESTDC').AsInteger;
        Result.PAYORSUBTYPESTDC := FieldByName('PAYORSUBTYPESTDC').AsInteger;
        Result.OWNER := FieldByName('OWNER').AsString;
        Result.HIDE := FieldByName('HIDE').AsBoolean;
        Result.IGRPUNIQUE := FieldByName('IGRPUNIQUE').AsInteger;
        Result.FORM := FieldByName('FORM').AsString;
        Result.GOVASSIGN := FieldByName('GOVASSIGN').AsBoolean;
        Result.CLAIMMAX := FieldByName('CLAIMMAX').AsInteger;
        Result.MEDIGAPCODE := FieldByName('MEDIGAPCODE').AsString;
        Result.EMCDEST := FieldByName('EMCDEST').AsString;
        Result.ASSIGNBENEFITS := FieldByName('ASSIGNBENEFITS').AsBoolean;
        Result.BATCHBILL := FieldByName('BATCHBILL').AsBoolean;
        Result.MEDIGAPPAYOR := FieldByName('MEDIGAPPAYOR').AsBoolean;
        Result.MEDPLANGUID := FieldByName('MEDPLANGUID').AsString;
        Result.SRXPLANGUID := FieldByName('SRXPLANGUID').AsString;
        Result.PAYPERCENT := FieldByName('PAYPERCENT').AsInteger;
        Result.LOCALNAME := FieldByName('LOCALNAME').AsString;
        Result.LOCALSTREET := FieldByName('LOCALSTREET').AsString;
        Result.LOCALCITY := FieldByName('LOCALCITY').AsString;
        Result.LOCALSTATE := FieldByName('LOCALSTATE').AsString;
        Result.LOCALZIP := FieldByName('LOCALZIP').AsString;
        Result.LOCALATTN := FieldByName('LOCALATTN').AsString;
        Result.LOCALPHONE := FieldByName('LOCALPHONE').AsString;
        Result.EHRSIGNOFF := FieldByName('EHRSIGNOFF').AsBoolean;
        Result.DISCONTINUED := FieldByName('DISCONTINUED').AsDateTime;
        Result.MODIFIED := FieldByName('MODIFIED').AsDateTime;
        Result.LEGACYPLAN := FieldByName('LEGACYPLAN').AsString;
        Result.LEGACYTYPE := FieldByName('LEGACYTYPE').AsString;
        Result.AUTHORIZE := FieldByName('AUTHORIZE').AsBoolean;
        Result.DISPENSEUPDATE := FieldByName('DISPENSEUPDATE').AsBoolean;
      end;
    end;

    function TPayorDM._newIDSTRING(const aFormat: String): String;
    begin
      Result := '';
      try
        with Q_Payor do
        try
          SQL.Clear;
          SQL.Add('SELECT NEWIDSTRING( "' + aFormat + '" ) AS GUID FROM system.iota');
          Open;
          Result := FieldByName('GUID').AsString;
          Close;
        except on E: EADSDatabaseError do
        begin
          ErrorMessage := '_newIDSTRING: ERRORCODE: ' + IntToStr(e.ACEErrorCode) +
            ' ERROR: ' + e.Message;
        end;
        end;
      finally

      end;
    end;

    procedure TPayorDM._pSetConnectionHandle(const Value: Integer);
    begin
      if T_Payor.Active then T_Payor.Close;
      CommonConnection.SetHandle(Value);
      OpenTable;
    end;

    procedure TPayorDM._pSetErrorMessage(const Value: String);
    begin
      WriteError('[TPayorDM]' + Value,LogFilename);
    end;

    procedure TPayorDM._psetSQL(const Value: TStringList);
    begin
      FSQL := Value;
    end;

    { TPayorRecord }

    procedure TPayorRecord.Clear;
    begin
      PAYORUNIQUE := 0;
      PAYORGUID := '';
      MASTERNAME := '';
      MASTERSTREET := '';
      MASTERCITY := '';
      MASTERSTATE := '';
      PAYORTYPESTDC := 0;
      MASTERZIP := '';
      MASTERATTN := '';
      MASTERPHONE := '';
      NEICCODE := '';
      RTCODE := '';
      STATEFILTER := '';
      NEICTYPESTDC := 0;
      PAYORSUBTYPESTDC := 0;
      OWNER := '';
      HIDE := False;
      IGRPUNIQUE := 0;
      FORM := '';
      GOVASSIGN := False;
      CLAIMMAX := 0;
      MEDIGAPCODE := '';
      EMCDEST := '';
      ASSIGNBENEFITS := False;
      BATCHBILL := False;
      MEDIGAPPAYOR := False;
      MEDPLANGUID := '';
      SRXPLANGUID := '';
      PAYPERCENT := 0;
      LOCALNAME := '';
      LOCALSTREET := '';
      LOCALCITY := '';
      LOCALSTATE := '';
      LOCALZIP := '';
      LOCALATTN := '';
      LOCALPHONE := '';
      EHRSIGNOFF := False;
      DISCONTINUED := 0;
      MODIFIED := 0;
      LEGACYPLAN := '';
      LEGACYTYPE := '';
      AUTHORIZE := False;
      DISPENSEUPDATE := False;
    end;

    { TPayors }

    procedure TPayors.Add(const aItem: TPayorRecord);
    begin
      SetLength(Items,Count + 1);
      Items[Count - 1] := aItem;
    end;

    function TPayors.CarriersList: TStrings;
    var
      I: Integer;
    begin
      Result := TStringList.Create;
      Result.Clear;
      SortbyName;
      try
      for I := 0 to Count - 1 do
        Result.Add(Items[I].LOCALNAME);
      finally

      end;
    end;

    procedure TPayors.Free;
    begin
      Items := Nil;
    end;

    function TPayors.GetPayorGuid(const aPAYORUNIQUE: Integer): String;
    var
      Idx:Integer;
    begin
      Result := '';
      Idx := IndexOfPayorUnique(aPAYORUNIQUE);
      if not (Idx = -1) then
        Result := Items[Idx].PAYORGUID;
    end;

    function TPayors.IndexOfIgrpUnique(const aIGRPUNIQUE: Integer): Integer;
    var
      I: Integer;
    begin
      Result := -1;
      for I := 0 to Count - 1 do
        if Items[I].IGRPUNIQUE = aIGRPUNIQUE then
        begin
          Result := I;
          Break;
        end;
    end;

    function TPayors.IndexOfPayorUnique(const aPAYORUNIQUE: Integer): Integer;
    var
      I: Integer;
    begin
      Result := -1;
      for I := 0 to Count - 1 do
        if Items[I].PAYORUNIQUE = aPAYORUNIQUE then
        begin
          Result := I;
          Break;
        end;
    end;

    procedure TPayors.SortByName;
    var
      fSort:TStringList;
      fParse:TStrings;
      I,Idx: Integer;
      fTempPayor:TPayors;
    begin
      fSort := TStringList.Create;
      fParse := TStringList.Create;
      fTempPayor.Items := Self.Items;
      fSort.Sorted := True;
      try
        for I := 0 to Count - 1 do
          fSort.Add(Items[I].LOCALNAME + #9 + IntToStr(I));
        Items := Nil;
        for I := 0 to fSort.Count - 1 do
          begin
            cbs.utils.ParseDelimited(fParse,fSort[I],#9);
            Idx := StrToInt(fParse[1]);
            Add(fTempPayor.Items[Idx]);
          end;
      finally
        fTempPayor.Free;
        fParse.Free;
        fSort.Free;
      end;
    end;

    function TPayors._pGetCount: Integer;
    begin
      Result := Length(Items);
    end;

    end.

1 个答案:

答案 0 :(得分:5)

你(很可能)双重释放一个字符串列表(并且永远不会释放至少一个)。问题出在你的'SQL'属性的设置器中(由'FSQL'字段支持):

procedure TPayorDM._psetSQL(const Value: TStringList);
begin
  FSQL := Value;
end;

在这里,您将丢失对现有字符串列表(LHS)的引用。请考虑以下情况:

你打电话

PayorDM.SQL := AStringList;

并且您在构造函数中创建的私有字段的引用已经消失,而是保留对“AStringList”的引用。在那之后你会破坏'AStringList',现在'FSQL'字段是一个陈旧的指针。在析构函数中,您调用

FSQL.Free;

你得到一个无效的指针操作。

将您的二传手改为:

procedure TPayorDM._psetSQL(const Value: TStringList);
begin
  FSQL.Assign(Value);
end;