Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Странность при работе с Record [D6, WinXP]


solomon ©   (2012-01-09 11:52:00) 

Давно не работал с записями, а сейчас вот столкнулся и не могу понять в чем дело.

Есть струкрута:

type
 TProjectStructure = record
   ProjectName: string[255];
   ProjectMode: word;
   AccountsName: tstringlist;  
end;

Структура описана в специальном юните в котором я храню общие для всего проекта процедуры, функции и вот теперь решил поместить туда же такую вот структуру данных.

В одном из модулей в обработчике события клика на кнопке я описываю локальную переменную ProjectPosting:

var
ProjectPosting:TProjectStructure;
begin
 //заполняем ProjectPosting
 ProjectPosting .ProjectName:=trim(Edit1.text);

//состояние проекта
ProjectPosting .ProjectMode:=1; //active

//список аккаунтов
ProjectPosting .AccountsName:=tstringlist.Create;
for i:=0 to CheckListBox1.Items.Count-1 do
  if CheckListBox1.Checked[i] then ProjectPosting.AccountsName.Add(CheckListBox1.Items.Strings[i]);

//Сохраняем структуру данных в стрим
TasksStream.WriteBuffer(ProjectPosting,SizeOf(TProjectStructure));

Если не написать ProjectPosting .AccountsName:=tstringlist.Create;
то получаю AV, что собственно логично.

Далее в другой форме идет чтение данных в обработчике клика мыши:

Var
ProjectTweetsPosting:TPostingProjectStructure; //описываем локальную переменную

Begin
      TasksStream.ReadBuffer(ProjectPosting,SizeOf(TPostingProjectStructure));
….
      if ProjectTweetsPosting.ProjectMode=1 then
       begin          
        for k:=0 to ProjectTweetsPosting.AccountsName.Count-1 do
         accs.Add(ProjectTweetsPosting.AccountsName.Strings[k]);
       end;

Странность в следующем. В последней форме почему-то уже не требуется AccountsName:=tstringlist.Create. Как это понимать, ведь ProjectTweetsPosting это локальная переменная на нее не должны распространяться действия произведенные в другом модуле где я писал «ProjectPosting.AccountsName:=tstringlist.Create;» ?


Плохиш   (2012-01-11 02:43:00) [1]


> Германн ©   (10.01.12 01:57) [19]

Как-будто не знаешь, для кого учебники писаны...


Германн   (2012-01-10 01:57:00) [2]

А TList вообще может хранить всё. Надо только учебник прочитать, чтобы узнать что такое "список".


Плохиш   (2012-01-10 01:42:00) [3]

TObjectList может хранить любые объекты в любых количествах и вариациях.


solomon   (2012-01-10 00:49:00) [4]

список объектов это что за зверь?

Вот скажем у меня есть 4 типа рекордов, у каждого свой набор полей:
TProjectStructure1 = record
TProjectStructure2 = record
TProjectStructure3 = record
TProjectStructure4 = record

Хранилище (в моем случае стрим) выглядит например следующим образом:
TProjectStructure3
TProjectStructure1
TProjectStructure2
TProjectStructure1
TProjectStructure3
TProjectStructure4

Это последовательность записи данных в стрим. Каждая структура (record) имеет свой размер, мы его знаем и может прочесть из стрима нужные данные вычислив смещение к нужной нам структуре.

Как видите в хранилище могут попадаться одинаковые объекты просто с разными данными внутри. И как всю эту кухню хранить ума не приложу? Может дадите небольшой код?


sniknik   (2012-01-09 23:28:00) [5]

> Что касается вопроса зачем стрим. Постараюсь пояснить. ... а каждый Records в свою очередь является хранилищем неких настроек необходимых потокам для работы.
пояснил. стрим не нужен. созданный в основном потоке объект передавай в дополнительный как есть, без стрима. как хранилище используй список объектов. все. зачем специально создавать себе проблемы?


нонамэ   (2012-01-09 23:17:00) [6]


> Хранить нужно данные, объект хранить не нужно.

Ну да... шкаф можно выкинуть


Сергей М.   (2012-01-09 23:01:00) [7]


> solomon ©   (09.01.12 22:18) [13]



> Хранить нужно данные, объект хранить не нужно


Хранение объекта и есть хранение данных, которые объект инкапсулирует.


solomon   (2012-01-09 22:18:00) [8]

Хранить нужно данные, объект хранить не нужно.

Что касается вопроса зачем стрим. Постараюсь пояснить. Есть основной поток программы. В нем создается стрим. В этот стрим добавляются Record`ы с разной структурой. После заполнения стрима программа начинаем работать. Запускаются потоки, каждый из которых, обращаясь через критическую секцию к стриму ищет в нем данные для себя. Найдя данные извлекаются и дальше в данном потоке обрабатываются, а в стрим возвращается метка того что данные были обработаны тогдато. Так происходит в цикле через заданные промежутки времени. Другими словами стрим представляет собой центральное хранилище данных типа Records, а каждый Records в свою очередь является хранилищем неких настроек необходимых потокам для работы.


sniknik   (2012-01-09 21:12:00) [9]

> как лучше поступать?
имхо, тебе сейчас лучше попытаться понять разницу между объектом и данными в нем...
вот зачем пытаешься сохранить в стрим объект? какой смысл? если он тебе нужен ну и "храни" его как есть объектом, если нужны данные то и сохраняй в стрим их.

и вообще НАФИГА тут стрим? только не говори удобно, это ничего не объясняет.
а то получается типа
- зачем вы храните ношеные носки в кастрюле?
- удобно!
- ??? а зачем?, суп же после может носками пахнуть!
- ... эээ, а вот кстати не поможете, как избавится от запаха?
- не храни их там, или объясни зачем. без "удобно". смысл.


Сергей М.   (2012-01-09 20:27:00) [10]


> как же компилятор рассчитывает ее размер?


Очень просто: SizeOf(TStringList) = SizeOf(TObject) = SizeOf(Pointer) = 4 (для Win32)

> как же происходит рассчет при чтении из стрима?

Точно так же: резервируется 4 байта под указатель на местоположение в памяти объекта TStringList


solomon   (2012-01-09 19:42:00) [11]

sniknik с классом пока не получается http://www.delphimaster.ru/cgi-bin/forum.pl?id=1326116288&n=0.Если все же решу оставить работу с records, как лучше поступать? Описывать структуру как я делал раньше централизовано в одном месте не вариант. Может тогда для каждого модуля описывать эту структуру отдельно и тогда у каждо из низ будет свое адресное пространство и пересечься они не смогут?

Но во всем этом деле с записью и чтением в стрим меня волнует другой вопрос.

Как можно корректно выделить память через SizeOf для переменной AccountsName: tstringlist; ? Точнее при записи в стрим все понятно, сколько создали итемов в tstringlist столько они памяти и заняли. А как же происходит рассчет при чтении из стрима? Я же не сообщаю процедуре TasksStream.ReadBuffer сколько у меня ожидается элементов в переменной AccountsName, как же компилятор рассчитывает ее размер?


sniknik   (2012-01-09 18:04:00) [12]

> Вопрос сохранится ли он в стрим.
все в твоих руках... напиши метод отдающий данные для стрима/и принимающий оттуда.

> В нем удобно хранить набор данных который в свою очередь состоить из разнородных данных - Record.
удобно это как есть без изменений хранить объекты, а с преобразованиями это уже не удобно.


solomon   (2012-01-09 16:48:00) [13]

Да про класс уже подумал, это был бы выход. Вопрос сохранится ли он в стрим. Покопаю. На счет того зачем нужен стрим. В нем удобно хранить набор данных который в свою очередь состоить из разнородных данных - Record.


sniknik   (2012-01-09 13:14:00) [14]

> инкассировано
;) да уж, исправило ошибку... - инкапсулированно.


sniknik   (2012-01-09 13:11:00) [15]

> Но фактически вести то себя все это дело будет как глобальная переменная.
нет, может и не повезти так что будет указывать на объект (перетрется другим), а может указатель будет указывать в другую область на код... после будешь "ловить" AV уже на нем, в совершенно не определенном месте, и иногда, ну вот звезды так сложились (условия)...

> я наверняка гденибудь да забуду
не забывай. создал - уничтожь как стало не нужным.
кстати тут, имхо, лучше не рекорд, а класс... конструктор, деструктор, все инкассировано, при освобождении общего внутренние ссылки на обьекты "нилятся" после освобождения. и все дела. никаких странностей не будет.
"сохранять в стрим" тоже можно по своему, можно вместе с данными внутреннго объекта, восстанавливать также. ну как и если требуется.


Сергей М.   (2012-01-09 13:06:00) [16]

А зачем вообще тебе стрим понадобился в ДАННОМ случае ?
Это довольно важно ..


solomon   (2012-01-09 12:35:00) [17]

Ок, пусть будет область памяти. Но фактически вести то себя все это дело будет как глобальная переменная. В одном месте программы записали данные, в другом их можно считать. Сергей, а как не отказывась от Record (уж очень он удобен для хранения разнородных данных и работы с TStream) реализовать разграничение адресных пространств так сказать ? Проблема в том, что в большой программе я наверняка гденибудь да забуду очистить за собой данные если они будут общими для всех и в итоге будут непонятные ошибки. Неужели придется в каждом модуле описывать один и тот же тип TProjectStructure = record ?


Сергей М.   (2012-01-09 12:26:00) [18]


> фактический все равно я получаю глобальную переменную так
> чтоли?


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


solomon   (2012-01-09 12:17:00) [19]

Так, ну хоть какая-то ясность. Значит фактический все равно я получаю глобальную переменную так чтоли?

Другими словами если в любом модуле моей программы я один раз опишу ProjectPosting:TPostingProjectStructure; и загружу в структуру данные, то после этого в любой другой форме, так же локально для нее описав ProjectPosting:TPostingProjectStructure я получу доступ к записанным ранее в данную структуру данным? Получается что-то вроде указателя, имена могут быть разные, а данные все равно хранятся только в одном месте...


Сергей М.   (2012-01-09 12:08:00) [20]


> это локальная переменная на нее не должны распространяться
> действия произведенные в другом модуле


Должны.
Процесс-то тот же самый, адресное пространство одно и то же.
Адрес объекта, единожды созданного при tstringlist.Create, записан в стрим и валиден при чтении из стрима, если в промежуток времени между записью и чтением объект не был уничтожен.


Наверх

Титульная страница Поиск, карта сайта Написать письмо