HLFX.Ru Forum (https://hlfx.ru/forum/index.php)
- Технические вопросы (https://hlfx.ru/forum/forumdisplay.php?forumid=20)
-- [CPP] this << F1 // OOP: субклассы в массивах (https://hlfx.ru/forum/showthread.php?threadid=4476)
Отправлено ~ X ~ 27-08-2014 в 08:42:
[CPP] this << F1 // OOP: субклассы в массивах
Под воздействием потенциальных пользователей пытался на днях дописать аврора-совместимую партикакал-систем. И тут ВНЕЗАПНО я задался вопросом...
Вот такие партиклы:
C++ Source Code:
8 | virtual void Render(const Vector &rt, const Vector &up, const int &rendermode, const bool &doubleside = false); |
12 | Vector m_vPos;// current position |
13 | Vector m_vPosPrev;// previous position |
14 | Vector m_vVel;// velocity |
15 | Vector m_vAccel;// acceleration (gravity, etc.) |
17 | float m_fEnergy;// should change from 1 to 0 during particle lifetime (linear) // do we really need this? |
18 | float m_fSizeX;// particle size in world units |
21 | float m_fColor[4];// color in RGBA (0...1) format |
22 | float m_fColorDelta[4]; |
24 | unsigned int m_iFlags; |
26 | int index;// index in my system, assigned in AllocateParticle() |
33 | // Что здесь важно - так это добавленеи новых свойств, занимающих немало места... |
34 | class CParticleAur : public CParticle |
38 | virtual void Render(const Vector &rt, const Vector &up, const int &rendermode, const bool &doubleside = false); |
40 | CParticleAur *m_pOverlay;// for making multi-layered CParticles |
41 | CParticleType *m_pType;// a pointer to its type |
Разница, какгрится, видна невооружённым тазом.
Хранятся они вот так:
C++ Source Code:
CParticle *m_pParticleList; |
Создаются так:
C++ Source Code:
m_pParticleList = new CParticleAur[m_iMaxParticles];// allocate custom class |
...а кагже правильно это всё обрабатывать? Моё программерское чутьё подсказывает, что вот это будет плохо:
C++ Source Code:
1 | void CPSAurora::Render(void) |
3 | // if (PointIsVisible(m_vecOrigin)) |
5 | // CPSAurora::BaseClass::Render(); |
7 | AngleVectors(g_vecViewAngles, NULL, v_right, v_up); |
8 | CParticleAur *p = NULL; |
9 | for (uint32 i = 0; i < m_iMaxParticles; ++i)// XDM3037: unstable m_iNumParticles; ++i) |
11 | p = (CParticleAur *)&m_pParticleList[i]; |
12 | if (p->m_fEnergy <= 0.0f || p->m_fSizeX <= 0.0f) |
...потому что m_pParticleList[i] нихрена не знает про CParticleAur и отсчитывает элементы в виде CParticle. Т.е. вот это должно работать:
C++ Source Code:
2 | CParticleAur *m_pParticleList = (CParticleAur *)m_pParticleList; |
3 | for (uint32 i = 0; i < m_iMaxParticles; ++i)// XDM3037: unstable m_iNumParticles; ++i) |
5 | p = (CParticleAur *)&pParticleList[i]; |
...так?__________________
Минутка полезного:
Бесплатный UT-подобный Half-Life mod.
Бесплатный редактор для 32-битных текстур. Без дотнета.
Бесплатный IDE для любых компиляторов и ЯП.
Бесплатная Windows-подобная ОС.
Проверка грамматики русского языка.
Чат по hl[fx]: [email protected]
Отправлено marikcool 27-08-2014 в 13:21:
Ты память криво читать будешь, поедположительно из соседних элементов. А на последнем получишь скорее всего краш
Я бы в твоем случае сделал бы массив указателей, работая с элементами массива приводил бы к нужному классу.
__________________
vk.com/skullcapstudios
Отправлено XaeroX 27-08-2014 в 13:23:
Цитата:
~ X ~ писал:
...так?
Да, так вполне должно работать.
Другой вопрос - а зачем ты заводил массив типа CParticle, а не CParticleAur?
Он где-то обходится в родительском классе? Тогда ты получишь ошибку в нём, из-за того, что он будет обходиться как массив CParticle с совершенно другим размером элемента.__________________
Отправлено marikcool 27-08-2014 в 13:24:
А не все верно, последовательность наследования перепутал. За указатель массива не парься, можешь хоть просто войд написать.
__________________
vk.com/skullcapstudios
Отправлено XaeroX 27-08-2014 в 13:25:
Цитата:
marikcool писал:
А на последнем получишь скорее всего краш
С чего бы?__________________
Отправлено marikcool 27-08-2014 в 13:27:
Цитата:
XaeroX писал:
Перепутал__________________
vk.com/skullcapstudios
Отправлено ~ X ~ 27-08-2014 в 13:49:
XaeroX почему же? Краш получен. Прям таки клубничный. Потому что CParticle намного меньше CParticleAur.
Проблема в том, что аллокатор и хранилище - внутри CParticleSystem - базового класса всех ПС (их много, очень много). И тащить свойства CParticleAur внутрь CParticle - это нарываться на падение производительности и перерасход памяти.
Вощем, я и сам подумывал над массивом указателей, но уж очень не хочется переписывать методы обращения в... 9 системах. :-/ По нескольку в каждой. Потом отлаживать, искать опечатки... Или накручивать абстракцию типа GetParticle(i), получая по распухшему стеку...
__________________
Минутка полезного:
Бесплатный UT-подобный Half-Life mod.
Бесплатный редактор для 32-битных текстур. Без дотнета.
Бесплатный IDE для любых компиляторов и ЯП.
Бесплатная Windows-подобная ОС.
Проверка грамматики русского языка.
Чат по hl[fx]: [email protected]
Отправлено XaeroX 27-08-2014 в 17:31:
Цитата:
~ X ~ писал:
почему же? Краш получен. Прям таки клубничный.
В той ситуации, что ты описал в 1 посте, краш невозможен с точки зрения банальной эрудиции.__________________
Отправлено FreeSlave 27-08-2014 в 18:27:
XaeroX, краш как раз очень даже возможен везде кроме первого элемента массива (по ясным причинам).
При таком преобразовании выкладка массива (обращение по элементам) становится невалидной. А так как указатель на таблицу виртуальных функций являются частью объекта, при таком раскладе происходит обращение по "мусорному" адресу и попытка найти там адрес нужной функции и выполнить её код.
Минимизрованный пример:
C++ Source Code:
8 | std::cout << "Base" << std::endl; |
13 | class Derived : public Base |
18 | std::cout << "Derived" << std::endl; |
25 | Derived* derives = new Derived[4]; |
26 | Base* bases = derives; |
27 | std::cout << sizeof(Base) << std::endl; |
28 | std::cout << sizeof(Derived) << std::endl; |
29 | std::cout << &derives[1] << ' ' << &bases[1] << std::endl; |
Решение: как уже говорилось, использовать массив указателей вместо массива значений.
Цитата:
~ X ~ писал:
не хочется переписывать методы обращения
Ты имеешь в виду различие между . и -> ?
Отправлено XaeroX 27-08-2014 в 18:42:
Народ, ну вы что... Сегодня же вроде не пятница...
Цитата:
~ X ~ писал:
C++ Source Code:
1 | CParticle *m_pParticleList = new CParticleAur[m_iMaxParticles];// allocate custom class |
4 | CParticleAur *m_pParticleList = (CParticleAur *)m_pParticleList; |
5 | for (uint32 i = 0; i < m_iMaxParticles; ++i)// XDM3037: unstable m_iNumParticles; ++i) |
7 | p = (CParticleAur *)&pParticleList[i]; |
Где в этом коде вылет будет, ткните мне пальцем.
Именно этот код привёл автор поста.__________________
Отправлено FreeSlave 27-08-2014 в 18:46:
Цитата:
XaeroX писал:
Где в этом коде вылет будет, ткните мне пальцем.
А, ты об этом
Ну если там всегда будут CParticleAur, пусть и под видом CParticle, то да. Только вот зачем тогда эти преобразования туда-сюда.
Отправлено XaeroX 27-08-2014 в 18:47:
Цитата:
FreeSlave писал:
А, ты об этом
Ну, как бы да.__________________
Отправлено ~ X ~ 28-08-2014 в 07:06:
XaeroX ты привёл мой "рабочий" пример. Прочти ещё раз текст вокруг вставок. Первый пример - краш, второй - работает.
забыл скопипастить:
C++ Source Code:
1 | class CPSAurora : public CParticleSystem |
3 | typedef CParticleSystem BaseClass; |
6 | CPSAurora(const char *filename, int attachment); |
7 | virtual ~CPSAurora(void); |
12 | class CParticleSystem : public CRenderSystem |
14 | typedef CRenderSystem BaseClass; |
19 | CParticle *m_pParticleList; |
Вобщем, похоже, что да, придётся делать массив указателей т.к. внутри базовой CParticleSystem идёт иногда итерация партиклов по типу CParticle.
Грёбаная аврора, как же я её ненавижу!! 
__________________
Минутка полезного:
Бесплатный UT-подобный Half-Life mod.
Бесплатный редактор для 32-битных текстур. Без дотнета.
Бесплатный IDE для любых компиляторов и ЯП.
Бесплатная Windows-подобная ОС.
Проверка грамматики русского языка.
Чат по hl[fx]: [email protected]
Отправлено ComradeAndrew 28-08-2014 в 10:28:
~ X ~:
Я так понимаю ты хочешь обойти краш, который возникает из-за обращения к CParticle []?
Можешь использовать функцию для получения элемента массива
C++ Source Code:
1 | CParticle* getCParticle(CParticle* particleList, int stride, int id) |
3 | return (CParticle*)((char*)particleList + stride*id); |
9 | CParticle *p = getCParticle(m_pParticleList, siszeof(CParticleAur), 1); |
Ну или перегрузить оператор [] для CParticle по аналогии. Должно работать. Если тебе не хочется переписывать под массив указателей. Но вряд ли это можно назвать лучшем способом (:
P.S. XaeroX прав: краша в том коде, который ты показывал быть не могло.
Отправлено ~ X ~ 28-08-2014 в 12:54:
ComradeAndrew я об этом уже говорил. Про гетпартикл. Но это уже ужос какой-то. А STL использовать ну никак не хочется.
Вобщем, думаю.
Наверное, всё-таки, придётся писать обёртку типа:
C++ Source Code:
3 | m_pParticleList[i] = new CWhateverParticle;// non-contiguous segments: BAD |
6 | CWhateverParticle *pContainer = new CWhateverParticle[n];// contiguous array |
8 | m_pParticleList[i] = &pContainer[i]; |
11 | m_pParticleList[i]->KillSomePigeons(); |
15 | delete m_pParticleList[i]; |
19 | m_pParticleList[i] = NULL; |
23 | delete [] m_pParticleList[0];// ??? |
Только вот с деаллокацией как-то сомнительно. Во втором варианте лучше бы запомнить контейнер.
Кроме того, трюк с выделением непрерывного массива не обязан гарантировать скорость обращения по указателям т.к. есть мнение, что компилятор И процессор могут оптимизировать , но не переходы по указателям...
[i]Добавлено 28-08-2014 в 16:34: