Solved

problem with the stringlist

Posted on 2009-05-12
8
339 Views
Last Modified: 2012-05-06
I created a procedure that query database to obtain the records.
I moved a qry to the class which returns StringList to the main form.
I am getting an error with the Eureka Log - multifree error leak.
Thus, makes me wonder maybe my code is incorrect when comes to freeing objects.
 


procedure TfrmDataViewerGUI.tcTest(const sqlStat: string);
var
  recordNum , i : integer;
  lsStations : TStringList;
  qStations : TDBOperator;
  n,k, gridCol, gridRow : integer;
begin
  lsStations := TStringList.Create;
  try
    qStations := TDBOperator.create(sqlStat,connectionString);
    try
      recordNum := qStations.recordCount;
      if recordNum <> 0 then
      begin
        lsStations := qStations.qryStations;
        for i := 0 to lsStations.Count - 1 do
        begin
          ShowMessage('station ' + lsStations[i]);
        end;
         qStations.closeConn;
      end
      else
      begin
        ShowMessage('no records');
      end;
    finally
 
      qStations.Free;
    end;
  finally
    lsStations.Free;
  end;
 
  ShowMessage('num of records  ' + IntToStr(recordNum));
 
end;
//----------------------------------------------------
unit uDB;
 
interface
uses
   Windows,Classes,StdCtrls,StrUtils,SysUtils, Messages,Dialogs
   ,ADODB;
 Type
    TDBOperator = Class(TObject)
    private
      FadoConn : TADOConnection;
      Fsql, FConnStr : string;
      FStationID : integer;
      FRecordCount : integer;
      FCountsList : TStringList;
      FstationList : TstringList;
 
 
 
    public
      constructor create (const ASql, AConnStr : string); overload ;
      constructor create (const Asql, AConnStr : string; const countID : integer);overload;
      function queryResultTCLowerGrid : TStringList;
      function qryStations : TStringList;
      function recordCount : integer;
      procedure closeConn;
 
end;
 
implementation
 
{ TDBOperator }
 
constructor TDBOperator.create(const ASql, AConnStr: string);
begin
  Fsql := Asql;
  FConnStr := AConnStr;
  FstationList := TStringList.Create;
end;
 
procedure TDBOperator.closeConn;
begin
  FstationList.Free;
end;
 
constructor TDBOperator.create(const Asql, AConnStr: string;
  const countID: integer);
begin
 
end;
 
// verify if there are any records per query
function TDBOperator.recordCount: integer;
var
  qry : TADOQuery;
  recNum : integer;
begin
  qry := TADOQuery.Create(nil);
  try
    qry.ConnectionString := FConnStr;
    qry.Close;
    qry.SQL.Clear;
    qry.SQL.Add(Fsql);
    qry.Open;
    //----------------------------------
    try
      qry.Active := true;
           except on e: EADOError do
           begin
                MessageDlg('Error while doing query', mtError,
                      [mbOK], 0);
 
              Exit;
          end;
       end; //end try adoQry.Active
    recNum := qry.RecordCount;
  finally
  FreeAndNil(qry);
  end;
 
  Result := recNum;
end;
 
// return qry results to the form
function TDBOperator.qryStations: TStringList;
var
  qry : TADOQuery;
  recNum : integer;
  i: integer;
begin
  qry := TADOQuery.Create(nil);
  try
    qry.ConnectionString := FConnStr;
    qry.Close;
    qry.SQL.Clear;
    qry.SQL.Add(Fsql);
    qry.Open;
    //----------------------------------
    try
      qry.Active := true;
           except on e: EADOError do
           begin
                MessageDlg('Error while doing query', mtError,
                      [mbOK], 0);
 
              Exit;
          end;
       end; //end try adoQry.Active
 
     recNum := qry.RecordCount;
     for i := 0 to recNum - 1 do
     begin
      FstationList.Add(qry.Fields.Fields[0].asstring);
      FstationList.Add(qry.Fields.Fields[1].asstring);
     end;
 
  finally
    qry.Free;
  end;
 
  result := FstationList;
 
end;
 
function TDBOperator.queryResultTCLowerGrid: TStringList;
begin
 
end;
 
 
 
end.

Open in new window

0
Comment
Question by:mordauth
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
8 Comments
 
LVL 14

Accepted Solution

by:
SteveBay earned 500 total points
ID: 24365993
change
   lsStations := qStations.qryStations;
to
   lsStations.Assign(qStations.qryStations);
0
 
LVL 12

Expert Comment

by:Hypo
ID: 24366113
I think I could point out a few things that you could aprove i your code, but anyway, the answer to your question about what causes the "multifree error leak" is because the function qryStations returns a TStringList that is owned by the TDBOperator class, and will be freed TDBOperator class, but it is also handed over to the Form that also free it. I see what you are trying to do with lsStations, but you should understand that when you assign an object with another object, then you don't copy the data of the objects, but instead you just replace the object pointers.

Change your code acordingly, and it will probably work.

regards
Hypo
procedure TfrmDataViewerGUI.tcTest(const sqlStat: string);
var
  recordNum , i : integer;
  lsStations : TStringList;
  qStations : TDBOperator;
  n,k, gridCol, gridRow : integer;
begin
  lsStations := TStringList.Create;
  try
    qStations := TDBOperator.create(sqlStat,connectionString);
    try
      recordNum := qStations.recordCount;
      if recordNum <> 0 then
      begin
        lsStations.Assign(qStations.qryStations);
        for i := 0 to lsStations.Count - 1 do
        begin
          ShowMessage('station ' + lsStations[i]);
        end;
         qStations.closeConn;
      end
      else
      begin
        ShowMessage('no records');
      end;
    finally
 
      qStations.Free;
    end;
  finally
    lsStations.Free;
  end;
 
  ShowMessage('num of records  ' + IntToStr(recordNum));
end;

Open in new window

0
 
LVL 12

Expert Comment

by:Hypo
ID: 24366154
too slow again... :)
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 14

Expert Comment

by:SteveBay
ID: 24366187
Answer quick, offer explainations later:)
0
 
LVL 12

Expert Comment

by:Hypo
ID: 24366220
Yep... but also my explaination was a bit flawed :(
This line: "but you should understand that when you assign an object with another object, then you don't copy the data of the objects, but instead you just replace the object pointers." can be missinterpreted as if I meant that the Assign() method replaces the poitners, but what I meant was of course that the assign operator := replaces the pointers. Sometimes I wish they would reinstate the edit function. :)
0
 
LVL 1

Author Comment

by:mordauth
ID: 24366286
Thanks for the asnwers,
Are you ok if I split the points ?
350 to Steve
150 to Hypo
0
 
LVL 12

Expert Comment

by:Hypo
ID: 24366307
You don't need to split the points for my sake, Steve answered your question first, and it was a correct answer. :)
0
 
LVL 14

Expert Comment

by:SteveBay
ID: 24366309
I agree that the assignment of Object pointers is one of the easiest ways to create hard to find bugs in Delhi applications. However, it can be a very powerful technique when used correctly.
0

Featured Post

Enroll in May's Course of the Month

May’s Course of the Month is now available! Experts Exchange’s Premium Members and Team Accounts have access to a complimentary course each month as part of their membership—an extra way to increase training and boost professional development.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
creating threads in delphi 1 196
Delphi...Split view - idea? 1 143
Delphi: sending SMS on android platform 1 98
Problem working with dynamic array - help 2 47
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…

737 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question