Форум: "Основная";
Текущий архив: 2014.06.29;
Скачать: [xml.tar.bz2];
ВнизСтранность при работе с Record Найти похожие ветки
← →
solomon © (2012-01-09 11:52) [0]Давно не работал с записями, а сейчас вот столкнулся и не могу понять в чем дело.
Есть струкрута:
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-09 12:08) [1]
> это локальная переменная на нее не должны распространяться
> действия произведенные в другом модуле
Должны.
Процесс-то тот же самый, адресное пространство одно и то же.
Адрес объекта, единожды созданного при tstringlist.Create, записан в стрим и валиден при чтении из стрима, если в промежуток времени между записью и чтением объект не был уничтожен.
← →
solomon © (2012-01-09 12:17) [2]Так, ну хоть какая-то ясность. Значит фактический все равно я получаю глобальную переменную так чтоли?
Другими словами если в любом модуле моей программы я один раз опишу ProjectPosting:TPostingProjectStructure; и загружу в структуру данные, то после этого в любой другой форме, так же локально для нее описав ProjectPosting:TPostingProjectStructure я получу доступ к записанным ранее в данную структуру данным? Получается что-то вроде указателя, имена могут быть разные, а данные все равно хранятся только в одном месте...
← →
Сергей М. © (2012-01-09 12:26) [3]
> фактический все равно я получаю глобальную переменную так
> чтоли?
Не глобальную переменную, а область памяти, выделенную в куче и имеющую сторого определенный адрес, доступный из любой точки программы.
← →
solomon © (2012-01-09 12:35) [4]Ок, пусть будет область памяти. Но фактически вести то себя все это дело будет как глобальная переменная. В одном месте программы записали данные, в другом их можно считать. Сергей, а как не отказывась от Record (уж очень он удобен для хранения разнородных данных и работы с TStream) реализовать разграничение адресных пространств так сказать ? Проблема в том, что в большой программе я наверняка гденибудь да забуду очистить за собой данные если они будут общими для всех и в итоге будут непонятные ошибки. Неужели придется в каждом модуле описывать один и тот же тип TProjectStructure = record ?
← →
Сергей М. © (2012-01-09 13:06) [5]А зачем вообще тебе стрим понадобился в ДАННОМ случае ?
Это довольно важно ..
← →
sniknik © (2012-01-09 13:11) [6]> Но фактически вести то себя все это дело будет как глобальная переменная.
нет, может и не повезти так что будет указывать на объект (перетрется другим), а может указатель будет указывать в другую область на код... после будешь "ловить" AV уже на нем, в совершенно не определенном месте, и иногда, ну вот звезды так сложились (условия)...
> я наверняка гденибудь да забуду
не забывай. создал - уничтожь как стало не нужным.
кстати тут, имхо, лучше не рекорд, а класс... конструктор, деструктор, все инкассировано, при освобождении общего внутренние ссылки на обьекты "нилятся" после освобождения. и все дела. никаких странностей не будет.
"сохранять в стрим" тоже можно по своему, можно вместе с данными внутреннго объекта, восстанавливать также. ну как и если требуется.
← →
sniknik © (2012-01-09 13:14) [7]> инкассировано
;) да уж, исправило ошибку... - инкапсулированно.
← →
solomon © (2012-01-09 16:48) [8]Да про класс уже подумал, это был бы выход. Вопрос сохранится ли он в стрим. Покопаю. На счет того зачем нужен стрим. В нем удобно хранить набор данных который в свою очередь состоить из разнородных данных - Record.
← →
sniknik © (2012-01-09 18:04) [9]> Вопрос сохранится ли он в стрим.
все в твоих руках... напиши метод отдающий данные для стрима/и принимающий оттуда.
> В нем удобно хранить набор данных который в свою очередь состоить из разнородных данных - Record.
удобно это как есть без изменений хранить объекты, а с преобразованиями это уже не удобно.
← →
solomon © (2012-01-09 19:42) [10]sniknik с классом пока не получается http://delphimaster.net/view/1-1326116288/. Если все же решу оставить работу с records, как лучше поступать? Описывать структуру как я делал раньше централизовано в одном месте не вариант. Может тогда для каждого модуля описывать эту структуру отдельно и тогда у каждо из низ будет свое адресное пространство и пересечься они не смогут?
Но во всем этом деле с записью и чтением в стрим меня волнует другой вопрос.
Как можно корректно выделить память через SizeOf для переменной AccountsName: tstringlist; ? Точнее при записи в стрим все понятно, сколько создали итемов в tstringlist столько они памяти и заняли. А как же происходит рассчет при чтении из стрима? Я же не сообщаю процедуре TasksStream.ReadBuffer сколько у меня ожидается элементов в переменной AccountsName, как же компилятор рассчитывает ее размер?
← →
Сергей М. © (2012-01-09 20:27) [11]
> как же компилятор рассчитывает ее размер?
Очень просто: SizeOf(TStringList) = SizeOf(TObject) = SizeOf(Pointer) = 4 (для Win32)
> как же происходит рассчет при чтении из стрима?
Точно так же: резервируется 4 байта под указатель на местоположение в памяти объекта TStringList
← →
sniknik © (2012-01-09 21:12) [12]> как лучше поступать?
имхо, тебе сейчас лучше попытаться понять разницу между объектом и данными в нем...
вот зачем пытаешься сохранить в стрим объект? какой смысл? если он тебе нужен ну и "храни" его как есть объектом, если нужны данные то и сохраняй в стрим их.
и вообще НАФИГА тут стрим? только не говори удобно, это ничего не объясняет.
а то получается типа
- зачем вы храните ношеные носки в кастрюле?
- удобно!
- ??? а зачем?, суп же после может носками пахнуть!
- ... эээ, а вот кстати не поможете, как избавится от запаха?
- не храни их там, или объясни зачем. без "удобно". смысл.
← →
solomon © (2012-01-09 22:18) [13]Хранить нужно данные, объект хранить не нужно.
Что касается вопроса зачем стрим. Постараюсь пояснить. Есть основной поток программы. В нем создается стрим. В этот стрим добавляются Record`ы с разной структурой. После заполнения стрима программа начинаем работать. Запускаются потоки, каждый из которых, обращаясь через критическую секцию к стриму ищет в нем данные для себя. Найдя данные извлекаются и дальше в данном потоке обрабатываются, а в стрим возвращается метка того что данные были обработаны тогдато. Так происходит в цикле через заданные промежутки времени. Другими словами стрим представляет собой центральное хранилище данных типа Records, а каждый Records в свою очередь является хранилищем неких настроек необходимых потокам для работы.
← →
Сергей М. © (2012-01-09 23:01) [14]
> solomon © (09.01.12 22:18) [13]
> Хранить нужно данные, объект хранить не нужно
Хранение объекта и есть хранение данных, которые объект инкапсулирует.
← →
нонамэ (2012-01-09 23:17) [15]
> Хранить нужно данные, объект хранить не нужно.
Ну да... шкаф можно выкинуть
← →
sniknik © (2012-01-09 23:28) [16]> Что касается вопроса зачем стрим. Постараюсь пояснить. ... а каждый Records в свою очередь является хранилищем неких настроек необходимых потокам для работы.
пояснил. стрим не нужен. созданный в основном потоке объект передавай в дополнительный как есть, без стрима. как хранилище используй список объектов. все. зачем специально создавать себе проблемы?
← →
solomon © (2012-01-10 00:49) [17]список объектов это что за зверь?
Вот скажем у меня есть 4 типа рекордов, у каждого свой набор полей:
TProjectStructure1 = record
TProjectStructure2 = record
TProjectStructure3 = record
TProjectStructure4 = record
Хранилище (в моем случае стрим) выглядит например следующим образом:
TProjectStructure3
TProjectStructure1
TProjectStructure2
TProjectStructure1
TProjectStructure3
TProjectStructure4
Это последовательность записи данных в стрим. Каждая структура (record) имеет свой размер, мы его знаем и может прочесть из стрима нужные данные вычислив смещение к нужной нам структуре.
Как видите в хранилище могут попадаться одинаковые объекты просто с разными данными внутри. И как всю эту кухню хранить ума не приложу? Может дадите небольшой код?
← →
Плохиш © (2012-01-10 01:42) [18]TObjectList может хранить любые объекты в любых количествах и вариациях.
← →
Германн © (2012-01-10 01:57) [19]А TList вообще может хранить всё. Надо только учебник прочитать, чтобы узнать что такое "список".
← →
Плохиш © (2012-01-11 02:43) [20]
> Германн © (10.01.12 01:57) [19]
Как-будто не знаешь, для кого учебники писаны...
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2014.06.29;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.002 c