Список строк Delphi в записи

Можно ли иметь в записи список строк? НАПРИМЕР

TImportStats = record
  ATotal:Integer;
  BTotal:String;
  AList:TStringist;
end;

и если я предполагаю, что мне нужно будет создать его перед использованием записи?


person colin    schedule 08.03.2011    source источник


Ответы (4)


Хотя это совершенно законно, возможно, будет разумным найти другой способ. Вы указали на проблему, когда сказали:

Я полагаю, мне нужно было бы создать его перед использованием записи

Более того, вам нужно найти хорошее время, чтобы его уничтожить. Если вы забудете это сделать, ошибок не будет, но в вашей программе будет утечка памяти.

Если запись является владельцем списка строк, вам может быть лучше поместить ее внутри класса. Таким образом, создание и уничтожение списка строк будет следовать шаблону конструктор / деструктор, с которым знакомы все разработчики Delphi.

Если запись не владеет списком строк, а просто принимает ссылку на нее в течение времени существования списка строк, тогда запись в порядке. Но если вы сделаете это таким образом, убедитесь, что время жизни записи содержится в пределах времени жизни списка строк, чтобы вы не переносили устаревшую ссылку.

person David Heffernan    schedule 08.03.2011
comment
Кроме того, OP важно понимать, что член записи объекта - это просто указатель на объект. То есть, если a и b - две записи типа TImportStats, тогда a := b сделает a и b указателем на один и тот же TStringList объект, поэтому любые изменения в a.AList также повлияют на b.AList и наоборот. Кроме того, старый AList из a останется в памяти, но не будет возможности получить к нему доступ, поэтому есть утечка памяти (если вы не сохранили указатель на объект где-то еще в своей программе). Конечно, Дэвид знает это; Я просто обращаюсь к ОП. - person Andreas Rejbrand; 08.03.2011

Да, это должно сработать. AList будет (не будет использоваться), пока вы не создадите список строк. Таким образом, вы можете использовать другие элементы записи, не создавая список строк, но вы должны создать элемент списка строк перед его использованием. Кроме того, вы несете ответственность за освобождение каждого списка строк, когда закончите.

person Chris Thornton    schedule 08.03.2011
comment
Это указатель, а не управляемый тип, я думаю, он будет указывать на произвольное место, пока ему что-то не будет присвоено. - person Sertac Akyuz; 08.03.2011
comment
Обратите внимание, что если вы используете запись в назначении, например R2: = R1, назначается только указатель. Обе записи будут указывать на тот же StringList. - person RobertFrank; 08.03.2011
comment
@Chris, @Sertac: Это зависит от того, где объявлено ImportStats: TImportStats. Если это локальная переменная, @Sertac прав - она ​​будет назначена, но указывает на мусор (и, конечно, не будет объекта TStringList). С другой стороны, если это глобальная переменная, объявленная где-то в разделе implementation, она будет заполнена нулями, то есть nil. - person Andreas Rejbrand; 08.03.2011
comment
И, конечно же, очень важно понять комментарий @Robert. - person Andreas Rejbrand; 08.03.2011
comment
@Sertac, экземпляр записи будет куда-то указывать, но я ожидаю, что поле AList будет нулевым, пока оно не будет назначено чему-то. - person Chris Thornton; 08.03.2011
comment
@Robert - и классная ошибка, которую легко представить здесь, заключается в том, что если вы назначаете этот способ, но думаете, что у вас действительно есть два строковых списка, вы A) получаете всевозможную путаницу, включая дублирование изменений (изменения одного влияют на другие ) и B) освобождение и обнуление одного освободит другое, но не обнулит его. - person Chris Thornton; 08.03.2011
comment
@Chris - Андреас прав, если он глобальный или в классе, он будет равен нулю, если локальный, то нет. - person Sertac Akyuz; 08.03.2011
comment
@ Крис, ты ошибаешься. Попробуйте procedure MyProc; var ImportStats: TImportStats; begin ShowMessage(BoolToStr(Assigned(ImportStats.AList), true)); end;. Обратите внимание, что Assigned(ImportStats.AList) в точности эквивалентно ImportStats.AList <> nil. - person Andreas Rejbrand; 08.03.2011
comment
@All - точка берется при nil vs 0. Но он все равно не будет использоваться, пока вы не создадите и не назначите список строк, если сценарий Роберта не является тем, что вы хотите. - person Chris Thornton; 08.03.2011
comment
@Andreas - добавьте эту строку в свой тест, и вы увидите, что список строк не готов к использованию: ShowMessage (IntToStr (ImportStats.AList.Count)); - person Chris Thornton; 08.03.2011
comment
@Chris: Конечно, он не готов к использованию! Нет TStringList объекта! Все, что я говорю, это то, что он назначен, где назначенный означает, что указатель не равен нулю. Как я уже сказал, до того, как TStringList будет создан и назначен члену AList, этот указатель будет указывать на мусор. То есть ваш оператор AList будет nil неверен (например, если запись является локальной переменной). AList не равно нулю, но указывает на мусор. - person Andreas Rejbrand; 08.03.2011
comment
Я отредактировал свой ответ, чтобы удалить ошибочную информацию о nil. - person Chris Thornton; 08.03.2011
comment
@ Крис, теперь я могу поставить тебе +1! :) - person Andreas Rejbrand; 08.03.2011
comment
@Chris, вы не можете использовать другие части записи, так же как не можете использовать сам StringList. Если запись создается в стеке, содержимое будет случайным. В этом отношении запись больше похожа на набор отдельных переменных: вы не можете использовать TStringList, объявленный как локальную переменную, перед ее инициализацией, так же как вы не можете использовать var i:Integer перед ее инициализацией. Нет разницы. - person Cosmin Prund; 08.03.2011
comment
@Cosmin: Я думаю, Крис просто сказал, что вы можете сделать ATotal := 5 прямо сейчас, но вы не можете сделать AList.Add('alpha'), если сначала не создадите объект с помощью AList := TStringList.Create. - person Andreas Rejbrand; 08.03.2011
comment
@Cosmin, конечно. Но вы можете сразу приступить к назначению простых членов. Моя точка зрения заключалась (и я считаю, что это был вопрос OP), что вы должны создать список строк перед его использованием. - person Chris Thornton; 08.03.2011
comment
@Chris, я думаю, объяснение просто двусмысленное, потому что назначение - не единственное возможное использование других элементов. Когда вы говорите you can use other elements of the record without ..., что мне мешает интерпретировать это как you can do SomethingElse := Record.SomeValue? И если присвоение - самая важная операция, которую нужно выполнить с элементами, вы также можете назначить StringList! - person Cosmin Prund; 08.03.2011

Если список строк будет использоваться только в локальной области записи TImportStats, вы можете посмотреть на Реализация значения StringList в Code Central.

Это позволяет избежать попытки создать, наконец, уничтожить накладные расходы.

person HMcG    schedule 08.03.2011

Я знаю, что, вероятно, поздно, но самый элегантный способ решить вашу проблему - это создать подкласс TStringList с ATotal и BTotal в качестве двух новых элементов в нем. Затем вы можете просто создавать и уничтожать его по своему усмотрению. Это простое и понятное решение.

person Fotis MC    schedule 14.09.2011