24 марта 2010

Delphi 2010: TDataSet.FreeBookmark – рудимент

   Часто бывает полезно отметить текущее положение курсора в DataSet'е так, чтобы позже можно было быстро возвратиться к этому месту. Delphi обеспечивает эту функциональную возможность с помощью закладок (Bookmark), для работы с которыми используются процедуры:
  • GetBookmark – устанавливает закладку на текущую запись;
  • BookmarkValid – проверяет, существует ли запись, на которую ссылается закладка;
  • GotoBookmark – позиционирует курсор на запись, на которую ссылается закладка;
  • FreeBookmark – освобождает системные ресурсы, используемые методом GetBookmark.
Думаю это знакомая многим конструкция:

Var
  q: TSDQuery;
  bm: TBookmark;
begin
  Try
    bm := q.GetBookmark; // делаем закладку
    // обрабатываем ds
  Finally
    If bm <> nil then
      begin
        If q.BookmarkValid(bm) then
          q.GotoBookmark(bm);
        q.FreeBookmark(bm);
      end;
  End;
end;

В Delphi 7 код FreeBookmark выглядит так:

procedure TDataSet.FreeBookmark(Bookmark: TBookmark);
begin
  FreeMem(Bookmark);
end;

В Delphi 2010 он – просто заглушка:

procedure TDataSet.FreeBookmark(Bookmark: TBookmark);
begin
  // No longer need to free bookmark since it's a TBytes now.
end;

   Т.е. FreeBookmark в Delphi 2010 – это уже пережиток прошлого и вызывать его больше не нужно. Таким образом, исходный код становится проще:

Var
  ds: TSDQuery;
  bm: TBookmark;
begin
  Try
    bm := q.GetBookmark; // делаем закладку
    // обрабатываем ds
  Finally
    If (bm <> nil) and q.BookmarkValid(bm) then
      q.GotoBookmark(bm);
  End;
end;

   P.S. А вот справочную систему Delphi 2010 подправить, как всегда, забыли. В ней есть раздел "DB.TDataSet.FreeBookmark" с описанием процедуры и рекомендацией ее использования. А раздел "Marking and Returning to Records" содержит строку "FreeBookmark frees the memory allocated for a specified bookmark when you no longer need it. You should also call DB.TDataSet.FreeBookmark before reusing an existing bookmark." и пример, где используется FreeBookmark :)

3 комментария:

  1. FreeBookmark - виртульный метод, и он с хорошей вероятностью может понадобится для освобождения ресурсов специфичных для унаследованной реализации. Поэтому в большом проекте я бы не стал рекомендовать нарушать задекларированный в VCL контракт.

    ОтветитьУдалить
  2. Анонимный24 марта, 2010 22:41

    Неверно,т.к. в общем случае Bookmark - это абстрактные данные, т.е. там может быть и обьект и OleVariant (как в ADO). В общем определяется реализацией TDataSet. По ADO кстати есть подозрение на утечку ресурсов:

    procedure TCustomADODataSet.GetBookmarkData(Buffer: TRecordBuffer; Data: Pointer);
    begin
    Initialize(POleVariant(Data)^);
    POleVariant(Data)^ := PRecInfo(Buffer).Bookmark;
    end;

    Здеcь не хватает вызова Finalize для декремента ссылок на ole обьект...

    procedure TDataSet.FreeBookmark(Bookmark: TBookmark);
    begin
    Finalize(POleVariant(Bookmark)^);
    // or:
    // POleVariant(Bookmark)^ := Null;
    end;

    ОтветитьУдалить
  3. Спасибо за инфу об ADO. Я отталкивался от стандартного TDataSet и от используемого мной TSDDataSet из SQLDirect. В SQLDirect переопределен только BookmarkValid.

    ОтветитьУдалить