Delphi programming blog
Источник: http://teran.karelia.pro/articles/item_4468.html
 

Generics + Array[x..y] of string = AV ?

Опубликовано 21.04.2011 г. 11:36

Новый пост на тему ошибок. Обычно если встречается ошибка, а с виду все правильно задаешься вопросом "delphi тупой или я дурак?". Не знаю как вы, но я уже неоднократно убеждался в последнем (:

Это уже 4й пост на тему ошибок. Из предыдущих трех один и вовсе ошибкой не был, в одном была моя ошибка, в третьем ошибка в сторонних компонентах. Теперь четвертый пост на тему ошибок. И в настоящий момент я опять думаю что не прав все таки Delphi. Предыстория весьма проста. При разработке некоторого набора классов, вдруг стала возникать ошибка при вызове деструктора объекта. Сначала не мог понять в чем дело, потом таки подумал головой, и решил, что надо проверить те изменения которые были внесены последними. А изменения были такими: Представим себе обобщенный класс, который имеет 4 объекта для выполнения запросов: select, insert, update, delete. Ну примерно как то так (сокращенно):
    TTest = class
      strict private
        FSelect : TADOQuery;
        FInsert : TADOQuery;
        ....
    end;
Идея в общем понятна. Где то потом заполняется SQL код для запросов и они используются. С целью большей оптимизации был проведен рефакторинг. Суть в том, что целых три запроса на Insert, Update, Delete нам не надо. Можно оставить только один, и хранить SQL код для каждого. FSelect впрочем оставить надо, ибо он должен поддерживаться актуальным. Итак, какие были проведены действия? Создание свойств SQLInsert : string и т.п. Здесь очень уместным является использование индексированных свойств, а для хранения запросов использовать массив. В конечном счете рефакторинг привел к такому виду класса:
    TTest = class(TObject)
      strict private
       type
        TQueryType = (qtSelect, qtInsert, qtUpdate, qtDelete);
       var
        FSQLQueries : array[TQueryType] of string;

        FSelect : TADOQuery;
        FQuery  : TADOQuery;

        function  GetSQL(qt : TQueryType) : string;
        procedure SetSQL(qt : TQueryType; value : string);
      public
        property SQLSelect : string index 0 read GetSQL write setSQL;
        property SQLInsert : string index 1 read GetSQL write setSQL;
        property SQLUpdate : string index 2 read GetSQL write setSQL;
        property SQLDelete : string index 3 read GetSQL write setSQL;
    end;

function TTest.GetSQL(qt: TQueryType): string;
begin
    result := FSQLQueries[qt];
end;

procedure TTest.SetSQL(qt: TQueryType; value: string);
begin
    FSQLQueries[qt] := value;
    if qt = qtSelect then
        FSelect.sql.text := value;
end;
и вот теперь, следующий код, приводит нас к AV при вызове деструктора объекта:
var a : TTest;
begin
     a := TTest.Create();
     a.Free();
end;

Сводим задачу к самому минимуму:

    TTest<T> = class
      strict private
        FData : array[0..1] of string;
    end;
Этого достаточно, для прихода к AV. Код программы для проверки:
type
    TTest<T> = class
      strict private
        FData : array[0..1] of string;
    end;
    TTestX = TTest<integer>;

var a :TTestX;

begin
  try
    a := TTestX.Create();
    a.Free();
  except
    on E: Exception do
      Writeln('epic fail: ' + E.ClassName, ': ', E.Message);
  end;
  readln;
end.
При этом:
  1. Если мы не используем обобщения, то проблем нет.
  2. Возникновение ошибки не зависит от того какой тип T мы используем.
  3. Ошибка возникает только для массива строк (String, AnsiString, WideString).
Как можно выйти из положения?
  1. Использовать PChar
  2. Использовать открытый массив.
  3. использовать другие структуры данных, но это накладные расходы.
Метки:  error  |  generics 

Комментарии

jack128
21.04.2011 в 13:16
>> Ошибка возникает только для массива строк (String, AnsiString, WideString).

Не только на строках, а на любых автофайнализируемых типах. На вариантах, интерфейсах - тоже глючит
ter
21.04.2011 в 14:02
да, вы правы.
Way cool! Some extremely valid points! I appreciate you penning this post and also the rest of the site is
extremely good.
shoe lifts
06.01.2018 в 11:48
Hi there, I found your website via Google at the same time as looking for a
similar subject, your web site got here up, it appears great.

I've bookmarked it in my google bookmarks.
Hello there, simply changed into alert to your blog via Google, and located that it's truly informative.
I'm gonna watch out for brussels. I'll be grateful
should you continue this in future. Numerous people will be benefited out of your writing.

Cheers!
- Имя
- e-mail*
- Сайт
вы можете использовать теги [i],[b],[code],[quote]
Дополнительно