Типы данных

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Re: Типы данных

Сообщение runewalsh » 10.12.2017 23:09:03

Azazaz
Во-первых, по сути это будут «record'ы с методами» (которыми их и предлагается заменять). Если же добавить полиморфизм, то объекты, созданные «на месте» (не через New), станут восприимчивы к slicing problem — скорее всего, классы выделяются в куче и передаются по указателям именно чтобы её исключить.

Во-вторых, если очень-очень надо, можно перекрыть NewInstance.
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 332
Зарегистрирован: 27.04.2010 00:15:25

Re: Типы данных

Сообщение Azazaz » 11.12.2017 16:13:30

runewalsh, попробуй разместить экземпляр класса на стеке функции/процедуры.
Azazaz
новенький
 
Сообщения: 41
Зарегистрирован: 21.04.2015 20:00:03

Re: Типы данных

Сообщение Cheb » 11.12.2017 16:50:38

разместить экземпляр класса на стеке функции/процедуры.

Зачем?
Они специально так устроены, чтобы избежать этого геморроя.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 619
Зарегистрирован: 06.06.2005 15:54:34

Re: Типы данных

Сообщение Дож » 11.12.2017 17:10:05

object'ы специально так устроены, чтобы избежать геморроя с постоянным размещением экземпляров в куче, всё верно :)
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 690
Зарегистрирован: 12.10.2008 16:14:47

Re: Типы данных

Сообщение Mikhail » 12.12.2017 12:09:31

В принципе можно сделать свой аллокатор для каждого класса.
Mikhail
постоялец
 
Сообщения: 490
Зарегистрирован: 24.10.2013 16:06:47

Re: Типы данных

Сообщение MylnikovDm » 12.12.2017 18:11:57

Лекс Айрин писал(а):
olegy123 писал(а):сейчас модно не локализировать переменные, а все толкать в стэк.


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

Локальные переменные располагаются в стеке не потому, что ими там проще манипулировать, а для обеспечения возможности рекурсивного вызова функций. Видимо вы ещё молоды и не застали того времени, когда у IBM PС был BIOS, у которого локальные переменные процедур и функций располагались не в стеке, а в общей памяти по фиксированным адресам, из-за чего были большие проблемы с организацией реальной многозадачности. IBM решил эту проблему, когда выпустил свои PS/2, у которых впервые в серии IBM PC был полностью рекурсивный BIOS и реально многозадачная OS/2. У остальных производителей это проблема была полностью решена только с переходом на платформу i386.

Что касается исходного вопроса и спора про классы и объекты.

Любая переменная класса всегда есть указатель на область памяти, где размещаются данные класса. Поэтому для упрощения написания кода символ ^ после имени переменной опускается. Именно поэтому с точки зрения компилятора писать "PForm(p)^.Caption" неправильно, а "TForm(p).Caption:=..;" правильно.

Что касается объектов, то это именно record с методами. То есть, когда вы пишите:

Код: Выделить всё
type
  TTest1 = object
    iT: integer;
    fp: double;
  end;

procedure TestProc;
var
  t1: TTest1;   
begin
  t1.iT := 4;
  t1.fp := 12.3;
end;


То, в отличие от классов, никаких ошибок в процессе выполнения не будет, поскольку под переменную t1 будет выделено необходимо количество памяти для хранения данных полей объекта TTest1. По этой же причине нет необходимости вызывать при выходе деструктор и явно освобождать память.

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

Так что у каждого подхода есть свои плюсы и минусы.
MylnikovDm
новенький
 
Сообщения: 76
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: Типы данных

Сообщение olegy123 » 12.12.2017 19:05:10

MylnikovDm писал(а):Так что у каждого подхода есть свои плюсы и минусы.

Спасибо, я это понял.

вот столкнулся с такой проблемой:
нужно сделать
BeginThread(@threadPaintPlane,@Params);
в Params нужно передать ряд значений.
Делается это тут:
procedure TGGUIPlane.paintGUI(constref Params: TGGUIPanitParams);
begin
BeginThread(@threadPaintPlane,@Params);
end;

где
TGGUIPanitParams = object
GLDirve:TGLDirveInfo;
obj:TObject;
end;

запускаемая функция:
function threadPaintPlane(pplane: pointer) : ptrint;

возникает вопрос о времени жизни Params? Пока получаю мусор.

есть идея глобализировать данные в куче путем GetMem(sizeof(TGGUIPanitParams))
и уничтожать при передачи внутри функции threadPaintPlane..

Добавлено спустя 2 минуты 2 секунды:
Можно сделать Events.Wait.. но это усложнить конструкцию.

Добавлено спустя 11 минут 24 секунды:
Еще возникла идея, добавить параметры в основной класс TGGUIPlane,
но этот вариант не лаконичен, так как предполагается, что TGGUIPlane будет виден разными потоками.. есть ли простое решение?
olegy123
энтузиаст
 
Сообщения: 826
Зарегистрирован: 25.02.2016 12:10:20

Re: Типы данных

Сообщение Mikhail » 12.12.2017 19:31:01

olegy123 писал(а):возникает вопрос о времени жизни Params? Пока получаю мусор.


Телепаты в отпуске, откуда Params берется? :)
Mikhail
постоялец
 
Сообщения: 490
Зарегистрирован: 24.10.2013 16:06:47

Re: Типы данных

Сообщение olegy123 » 12.12.2017 19:37:06

Mikhail писал(а):Телепаты в отпуске, откуда Params берется?

Упрощю:
Код: Выделить всё
procedure TGGUIPlane.paintGUI(const GLDirve: TGGLDirve);
var
  Params:TGGUIPanitParams;
begin
  p.obj:=Self;
  p.GLDirve:=GLDirve;
BeginThread(@threadPaintPlane,@Params);
end;
где GLDirve = это есть TOpenGLControl

Добавлено спустя 2 минуты 1 секунду:
Тут вопрос про
BeginThread(ThreadFunction : tthreadfunc;p : pointer)
и p : pointer
как я понял p : pointer должен быть глобальный(или долгоживущий)

Добавлено спустя 4 минуты 13 секунд:
мне же важно в (p : pointer) упаковать более двух значений. Эти значения могут прийти с разных потоков.
Т.е. время жизни должно быть коротким и одновременно достаточным для передачи в поточную функцию.
olegy123
энтузиаст
 
Сообщения: 826
Зарегистрирован: 25.02.2016 12:10:20

Re: Типы данных

Сообщение Mikhail » 12.12.2017 19:44:56

olegy123 писал(а):
Mikhail писал(а):Телепаты в отпуске, откуда Params берется?

Упрощю:
Код: Выделить всё
procedure TGGUIPlane.paintGUI(const GLDirve: TGGLDirve);
var
  Params:TGGUIPanitParams;
begin
  p.obj:=Self;
  p.GLDirve:=GLDirve;
BeginThread(@threadPaintPlane,@Params);
end;
где GLDirve = это есть TOpenGLControl

Добавлено спустя 2 минуты 1 секунду:
Тут вопрос про
BeginThread(ThreadFunction : tthreadfunc;p : pointer)
и p : pointer
как я понял p : pointer должен быть глобальный(или долгоживущий)


В данном случае, до конца работы PaintGui. В общем не правильно. :)
Mikhail
постоялец
 
Сообщения: 490
Зарегистрирован: 24.10.2013 16:06:47

Re: Типы данных

Сообщение Лекс Айрин » 12.12.2017 20:13:33

olegy123 писал(а):Т.е. время жизни должно быть коротким и одновременно достаточным для передачи в поточную функцию.


Pointer может быть разным. Но если он упоминается где-то в нескольких местах, то он должен быть объявлен, как и любая переменная/тип в месте доступном для всех мест употребления.
Так же есть и возможность сохранить значение указателя во внешней переменной или как результат функции. Сложность работы с указателями в том, что всегда надо помнить, активен он или обнулен. Поэтому проще сначала отладить и инкапсулировать создание/удаление/манипуляцию указателями, а потом реализовать логику в которой они нужны. Но если есть возможность обойтись без указателей, то лучше ею воспользоваться.

olegy123 писал(а):мне же важно в (p : pointer) упаковать более двух значений. Эти значения могут прийти с разных потоков.


А в чем проблема?
Код: Выделить всё
PRec= ^Pec;
Rec=record
First,Second.... Last:Pointer;
End;

Конечно, тут геморроя с определением чей и каким типом инициирован указатель море, но они решаются примерно также -- созданием соответствующей записи вместе со ссылками. В сумме, конечно, объекты в использовании проще, чем голые и типизированные ссылки.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 4200
Зарегистрирован: 19.02.2013 16:54:51

Re: Типы данных

Сообщение olegy123 » 12.12.2017 20:39:07

Ладно, я тут пересмотрел структуру. Возможно будет проще.
olegy123
энтузиаст
 
Сообщения: 826
Зарегистрирован: 25.02.2016 12:10:20

Re: Типы данных

Сообщение MylnikovDm » 12.12.2017 22:28:03

Пока не до конца ясно, как в целом работает ваша система, но вам в любом случае необходимо чётко определить политику по работе с памятью. То есть, кто и в какой момент создаёт объекты, и кто и в какой момент их потом уничтожает. При этом создание объекта через TObject.Create всегда создаёт его из общего пула памяти, так что его можно считать глобальным объектом. Тут важно не потерять на него указатель, поскольку иначе вы уже не сможете освободить память, выделенную под объект.

Следующая проблема возникает, когда у вас есть слишком много ссылок на ваш объект, которые хранятся в самых разных местах, поскольку встаёт вопрос о том, существует ли ещё этот объект или где-то он уже был уничтожен. Когда это на самом деле нужно, то приходится городить достаточно сложные механизмы с наблюдением или уведомлениями, чтобы все владельцы ссылок вовремя у себя пометили, что объект был удалён.

Что касается необходимости передавать несколько параметров через один pointer, то что мешает для этой цели использовать TObjectList, в который вы можете поместить сколько угодно параметров?

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

Все объекты типа TGGUIPanitParams или наследников от него должны быть созданы и заполнены значениями до вызова BeginThread(@threadPaintPlane,@Params); После вызова данной функции какой-либо доступ к ним должен быть запрещён. Но это требование по доступу, само собой, не распространяется на объекты, ссылки на которые записаны в TGGUIPanitParams, как, например, ваш p.GLDirve. Хотя тут тоже необходимо определиться с доступом по изменению. Если изменения в других потоках необходимы, то нужно будет делать критические секции. В том числе, в этом случае может понадобиться запрещать изменения и запускать критическую секцию внутри кода threadPaintPlane, чтобы не получилось так, что одну часть изображения вы отрисовали с одними значениями, а вторую часть изображения с другими, поскольку один из параллельных потоков решил их изменить.

В конце работы функции threadPaintPlane она должна уничтожить TObjectList со всеми вложенными в него объектами типа TGGUIPanitParams.

Кстати, у вас тоже возникает проблема контроля за тем, что ваши основные объекты типа TGLDirve, ссылки на которые вы передаёте внутри TGGUIPanitParams, не были уничтожены где-то в другом параллельном потоке, пока вы выполняли какую-то часть отрисовки. Чтобы упростить себе работу, возможно иметь смысл порождать ваши TGLDirve от TPersistent и использовать встроенные в него механизмы контроля и защиты.
MylnikovDm
новенький
 
Сообщения: 76
Зарегистрирован: 15.02.2007 21:26:10
Откуда: Челябинск

Re: Типы данных

Сообщение olegy123 » 13.12.2017 11:52:37

MylnikovDm писал(а):Пока не до конца ясно, как в целом работает ваша система, но вам в любом случае необходимо чётко определить политику по работе с памятью.

Все правильно, я пересмотрел работу с элементами. Даже получилось на много лучше и красивее.. Правда налагает определенные правила, но это даже лучше.
Тут важно понять где элемент должен присутствовать [1=1] [1=~] [~=1] может даже [~=~].
Выделил отдельный GL контекст для каждого графического элемента, который отображает где он должен быть показан. Теперь элемент чтобы обновится может сам управлять GL контекстами.
Картинку получил.
olegy123
энтузиаст
 
Сообщения: 826
Зарегистрирован: 25.02.2016 12:10:20

Re: Типы данных

Сообщение olegy123 » 14.12.2017 12:37:20

Подскажите, а random - дает равномерное случайное распределение?
olegy123
энтузиаст
 
Сообщения: 826
Зарегистрирован: 25.02.2016 12:10:20

Пред.След.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4

Рейтинг@Mail.ru