Delphi - Как освободить память из TDataSet? - PullRequest
2 голосов
/ 25 октября 2011

D2010, Win7 64bit. Здравствуйте,

У меня событие buttonClick с необходимостью обработки TDataSet, открытого в другой подпрограмме ... GetDBGenericData.

Функция GetDBGenericData возвращает TDataSet. Эта процедура в основном берет компонент tQuery, устанавливает его свойство SQL и открывает его. Затем он возвращает TDataSet к моему нажатию кнопки.

procedure TForm1.Button2Click(Sender: TObject);
var
DS : TDataSet;
begin

DS := TDataSet.Create(nil);
DS := GetDBGenericData(dbSOURCE, 'LIST_ALL_SCHEMAS', [] );

while Not DS.EOF do
   begin
   ShowMessage(DS.FieldByName('USERNAME').AsString);
   DS.Next;
   end;

DS.Close;
DS.Free;

Моя проблема - понимание DS. Я создаю это здесь в этой рутине. Я "назначаю" его TDataSet, который указывает на компонент. Если я не освобождаю его, у меня есть утечка памяти (как сообщает EurekaLog). Если я сделаю это бесплатно, я получу AV при следующем запуске этой процедуры. (особенно внутри процедуры GetDBGenericData).

Я думаю, что происходит то, что DS получает назначение (а не копирование) для возвращаемого TDataSet, поэтому, по сути, я освобождаю оба DS в этой подпрограмме и tQuery в GetDBGenericData, когда я сделать бесплатно.

Как «разорвать» связь, а затем удалить память, связанную ТОЛЬКО с той, которую я динамически создаю.

Спасибо, GS

1 Ответ

4 голосов
/ 25 октября 2011

Если вашей переменной DS назначается другая TDataSet с помощью GetDBGenericData, вы не должны ни Create, ни Free указывать ее.Вы просто используете его для ссылки на существующий набор данных.

procedure TForm1.Button2Click(Sender: TObject);
var
  DS : TDataSet;
  UserNameField: TField;  // Minor change for efficiency
begin
  DS := GetDBGenericData(dbSOURCE, 'LIST_ALL_SCHEMAS', [] );

  // Call FieldByName only once; no need to create or
  // free this either.
  UserNameField := DS.FieldByName('USERNAME');

  while not DS.Eof do
  begin
    ShowMessage(UserNameField.AsString);
    DS.Next;
  end;

  // I'd probably remove the `Close` unless the function call
  // above specifically opened it before returning it.
  DS.Close;
end;
...