![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Странность при работе с 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, записан в стрим и валиден при чтении из стрима, если в промежуток времени между записью и чтением объект не был уничтожен.