Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > правомерно ли такое


Автор: borisbn 1.7.2012, 11:00
Здравствуйте.

Имеется статический массив объектов
Код
Object s_objects[ I ][ J ][ K ];

Object наследуется от интерфейса IFace
Код

class IFace {
public:
    virtual void foo() = 0;
};
class Object : public IFace {
public:
    virtual void foo();
};

В функции Object::foo() мне нужно узнать свои индексы в массиве s_objects. Делаю я это так
Код
void Object::foo() {
    int idx = this - &s_objects[ 0 ][ 0 ][ 0 ];    // <----- это - нормально ???
    int k = idx % K;
    int j = ( idx / K ) % J;
    int i = ( idx / k / J ) % I;
}

Меня терзают смутные сомнения:
- правомерна ли такая запись ?
- будет ли это работать на всех платформах, на всех компиляторах, при всех настройках компиляции ?
Ещё меня смущает, что Object::foo() будет вызываться из кода, который знает только о IFace. Т.е. как-то так
Код
IFace * p = &s_objects[ i ][ j ][ k ];
p->foo();


Заранее спасибо.

P.S. Хранить в Object свои индексы - не предлагать, т.к. этих объектов будет огромное количество (суммарно более 4 ГБ) и увеличивать класс на 3 int'а я уже не могу.

Добавлено через 5 минут и 50 секунд
P.P.S. А может кто-нибудь подскажет мне в связанной с этим вопросом теме - http://forum.vingrad.ru/forum/topic-353079.html ?

Автор: Randajad 1.7.2012, 13:04
Правомерно.

Автор: volatile 1.7.2012, 13:36
borisbn, а какова необходимость именно в непрерывном массиве?

То что ваш код, приведенный здесь, будет работать только при непрерывном массиве, это понятно.
Есть ли какие -то другие веские причины, почему нужен именно непрерывный массив.
Если веских причин в непрерывном массиве нет, то решится первая проблема
Цитата(borisbn @  1.7.2012,  11:00 Найти цитируемый пост)
 в связанной с этим вопросом теме 

и будем решать эту. (чуток по другому).

зы: в любом случае (непрерывный или прерывный),  синтаксис будет одинаков: objects [i][j][k];

Автор: borisbn 1.7.2012, 13:54
Цитата(volatile @  1.7.2012,  13:36 Найти цитируемый пост)
какова необходимость именно в непрерывном массиве?

В принципе, необходимости нет. Однако, я бы хотел, чтобы получение этих индексов было бы максимально быстрое, поэтому и сделал массив непрерывным.
В общем, суть задачи такова:
1) мне заранее известно количество этих объектов (а именно: кол-во строк, столбцов и ... как бы обозвать... кол-во таблиц)
2) в функции foo() мне необходимо знать № таблицы, № строки и № столбца объекта, у которого эта foo() вызвана
3) хранить эти индексы в объекте я не могу (и так много памяти кушаю)

P.S. я бы хотел на этапе компиляции/линковки знать, что память будет выделена. Не хотелось бы узнать о нехватке памяти в рантайме...

Цитата(volatile @  1.7.2012,  13:36 Найти цитируемый пост)
в любом случае (непрерывный или прерывный),  синтаксис будет одинаков: objects [i][j][k];

у меня как раз обратная задача - по имеющемуся указателю вычислить i, j и k 

Автор: volatile 1.7.2012, 15:57
Цитата(borisbn @  1.7.2012,  13:54 Найти цитируемый пост)
по имеющемуся указателю вычислить i, j и k 

borisbn, я чуток подумал. Действительно вычислить индекс по адресу, можно оптимально только при непрерывном массиве.
Вначале думал просто сделать массив указателей на указатели на s_objects []
Но там вычисление индексов будет не простым.
Понадобится что-то типа двух дополнительных индексов (map'ов) , размерами один I, другой J. (впрочем это относительно не много) + время на доступ к этим мапам.

В общем, не знаю. Как крайний вариант, если не выйдет выделить весь массив сразу,
могу накалякать версию с двумя мапами. Если хотите.
Или вас это в принципе не устроит?

Автор: borisbn 1.7.2012, 16:33
Цитата(volatile @  1.7.2012,  15:57 Найти цитируемый пост)
могу накалякать версию с двумя мапами. Если хотите.
Или вас это в принципе не устроит?

спасибо, но я думаю, что справлюсь ))
Что ж... раз все считают такую конструкцию правомерной, то ИМХО нечего выдумывать... оставлю так. Единственное, что меня беспокоит, так это то, что мне могут просто не дать выделить такой большой массив в статической памяти...
Хотя... не беда. Я ж могу и в динамической памяти выделить непрерывный участок... Опять же - если дадут.
Всем спасибо. Закрываю, но хотелось бы услышать советы по соседней теме - http://forum.vingrad.ru/forum/topic-353079.html

Автор: volatile 1.7.2012, 16:45
Цитата(borisbn @  1.7.2012,  16:33 Найти цитируемый пост)
спасибо, но я думаю, что справлюсь ))

ок.

Цитата(borisbn @  1.7.2012,  11:00 Найти цитируемый пост)
    int i = ( idx / k / J ) % I;

это конечно опечатка, но вдруг вы не заметили
 k  K

Автор: Randajad 1.7.2012, 17:54
Цитата

P.S. я бы хотел на этапе компиляции/линковки знать, что память будет выделена. 


Такого не бывает. Все узнается только в рантайме. Даже если линкер и запишет размер памяти, которая нужна, не факт, что OS при запуске вашей программы не пошлет ее далеко.

Автор: volatile 1.7.2012, 18:49
Цитата(Randajad @  1.7.2012,  17:54 Найти цитируемый пост)
Такого не бывает.

Randajad, borisbn просто не совсем точно выразился. 
в соседней темке, он объяснил
Цитата(borisbn @  1.7.2012,  14:33 Найти цитируемый пост)
Я, пожалуй, неправильно высказался... Я НЕ хочу в своей программе проверять, выделилась ли память после new. Я хочу, чтобы стандартный загрузчик без моего участия либо выделил память и дал бы моей программе работать, либо сам бы ругнулся на недостаток памяти 


Автор: mes 1.7.2012, 19:07
Цитата(borisbn @  1.7.2012,  10:00 Найти цитируемый пост)
- будет ли это работать на всех платформах, на всех компиляторах, при всех настройках компиляции ?

при множественном наследовании не всегда..

Добавлено через 5 минут и 57 секунд
Цитата(borisbn @  1.7.2012,  12:54 Найти цитируемый пост)
1) мне заранее известно количество этих объектов (а именно: кол-во строк, столбцов и ... как бы обозвать... кол-во таблиц)


Цитата(borisbn @  1.7.2012,  10:00 Найти цитируемый пост)
IFace * p = &s_objects[ i ][ j ][ k ];
p->foo();

почему бы не так :
Код

void foo(.. i, .. j, .. k)
{
  if ( IFace * p = &s_objects[ i ][ j ][ k ];)
     p->foo(j,i,k);
}

foo(i,j,k);



Добавлено через 10 минут и 58 секунд
Цитата(borisbn @  1.7.2012,  10:00 Найти цитируемый пост)
P.S. Хранить в Object свои индексы - не предлагать, т.к. этих объектов будет огромное количество (суммарно более 4 ГБ) и увеличивать класс на 3 int'а я уже не могу.

а нужно ли хранить сами обьекты, может приспособленца (flyweight pattern) взять в помощь ?

Автор: math64 2.7.2012, 07:52
Код

struct ObjectData { ... };
ObjectData data[I][J][K];
class Object : publc IFace {
public:
Object(int _i, int _j, int _k) : i(_i), j(_j), k(_k) { pdata = &data[i][j][k]; }
void foo();
private:
ObjectData* pdata;
int i,j,k;
}

void foo() {
for(int i =0; i < I; i++)
  for(int j =0; j < J; j++)
    for(int k =0; k < K; k++) {
       Object o(i,j,k);
       IFace* iface = &o;
       iface->foo();
    }
}

Потребности в памяти уменьшатся - в ObjectData не будет указателя на таблицу виртуальных методов, но потеряешь в скорости (на каждом обороте цикла объект создаётся заново)

Автор: borisbn 2.7.2012, 08:33
Цитата(volatile @  1.7.2012,  16:45 Найти цитируемый пост)
это конечно опечатка

 smile
как Вы понимаете, в настоящей программе у меня переменные немного по-другому называются  smile 

Цитата(mes @  1.7.2012,  19:07 Найти цитируемый пост)
при множественном наследовании не всегда..

ясно. спасибо. учту.
Цитата(mes @  1.7.2012,  19:07 Найти цитируемый пост)
почему бы не так :

на самом деле, тот, кто вызывает foo() ничего об этом статическом массиве не знает. У него есть только указатель, да и то на базовый класс.

Цитата(mes @  1.7.2012,  19:07 Найти цитируемый пост)
а нужно ли хранить сами обьекты, может приспособленца (flyweight pattern) взять в помощь ?

первый раз слышу. /me пошёл читать про flyweight pattern

math64, 
Цитата(borisbn @  1.7.2012,  11:00 Найти цитируемый пост)
Хранить в Object свои индексы - не предлагать, т.к. этих объектов будет огромное количество (суммарно более 4 ГБ) и увеличивать класс на 3 int'а я уже не могу.


Добавлено через 12 минут и 14 секунд
Цитата(borisbn @  2.7.2012,  08:33 Найти цитируемый пост)
/me пошёл читать про flyweight pattern

Кажется, не подойдёт, т.к. я не хочу выделять память под каждый объект из-за накладных расходов.
вот - http://fahrenheit2539.blogspot.com/2012/05/memory-allocation-overhead-field-study.html - недавно прочитал про накладные расходы в new и ужаснулся... оттуда и задумался о большом статическом массиве

Автор: math64 2.7.2012, 08:55
http://en.wikipedia.org/wiki/Flyweight_pattern
borisbn, В моём варианте Object - временный объект (ну, чтобы удовлетворить Вашему требованию переименуем его в XObject), в приведённом мной цикле он существует в одном экземляре внутри цикла, добавленние в него индексов не увеличивает потребление памяти в программе, а за счёт того, что в большом массиве будет не объект, а структрура без таблицы виртуальных методов (её можно ещё упаковать, если возможно), потребление памяти уменьшается. Но объект нужно конструировать каждый раз заново, когда он понадобится и удалять по ненадобности (данные, по которым можно восстановить объект, сохраняются) - скорость выполнения уменьшится. Это тоже паттерн проектирования, но как он называется, не помню.

Автор: math64 2.7.2012, 09:30
Почитал про FlyWeightPattern - фактически, мой код - его упрощенная версия, new, как видите, не обязателен. Важно выделить из объекта упакованные данные, по которым всегда можно восстановить объект и тогда объект нужно создавать только тогда, когда он нужен для работы.

Автор: mes 2.7.2012, 21:56
Цитата(borisbn @  2.7.2012,  07:33 Найти цитируемый пост)
Кажется, не подойдёт, т.к. я не хочу выделять память под каждый объект из-за накладных расходов.

опубликуйте задачу, которую Вы пытаетесь решить таким замысловатым способом, тогда возможно можно будет более точно сказать, что подходит, а что нет..

Цитата(borisbn @  2.7.2012,  07:33 Найти цитируемый пост)
недавно прочитал про накладные расходы в new и ужаснулся... оттуда и задумался о большом статическом массиве 

опять игра слов.. статический массив или массив в статической памяти smile.. 

Автор: math64 3.7.2012, 08:00
Цитата(mes @  2.7.2012,  21:56 Найти цитируемый пост)
опубликуйте задачу, которую Вы пытаетесь решить таким замысловатым способом

Пока что borisbn не показал причин, почему нельзя применить FlyWeightPattern - возможно, главная в том, что придётся переписать весь код.
Примеры на C++ применения FlyWeightPattern в описаниях паттерна не очень удачны, они в большинстве они просто переписаны с Java.
В Java используется фабрика, которая создаёт объекты с помощью new, а ненужные объекты удаляются сборщиком мусора. В C++ можно создавать объекты и без new - но, да, возможно придётся написать аналог сборщика мусора, которого нет в C++.
Если нужно работать одновременно работать с I*J*K объектами Object, то FlyWeightPattern не подойдёт. Но я не могу представить алгоритма, при котором это было действительно нужно.
Но если нужно одновременно работать, например, с центральным объектом и его соседями (одновременно нужно 27 Object'ов), то можно пойти на то, что в Object будут храниться его координаты.

Автор: borisbn 3.7.2012, 08:49
Цитата(mes @  2.7.2012,  21:56 Найти цитируемый пост)
опубликуйте задачу, которую Вы пытаетесь решить таким замысловатым способом

Дело в том, что программа изначально не моя, а опенсоурсная. Мне нужно переделать её для работы с нашим "железом". В оригинальной программе в классе Object хранились индексы, и объект создавался когда было нужно при помощи new. Разница заключается в том, что в оригинальной программе одновременно создавалось не более 16 000 объектов, а в моём варианте будет порядка 1 млрд объектов. Поэтому я и пытаюсь уменьшить размер каждого объекта.
В оригинале во всевозможные функции обработки достаточно было передавать указатель на объект, а его индексы можно было спросить у него. Я же не хочу создавать такое кол-во объектов динамически и хочу избавиться от индексов

Цитата(mes @  2.7.2012,  21:56 Найти цитируемый пост)
 статический массив или массив в статической памяти

не очень понимаю разницу

Автор: math64 3.7.2012, 09:15
Пока не вижу другой причины отказа от FlyWeightPattern. кроме нежелания (почти) полностью переписывать программу.
Для того, чтобы Вы поняли, что такое FlyWeightPattern, приведу реальный пример его использования в Qt - QItemDelegate.
Представьте, что в оригинальной программе вместо QTableView использовались для каждой ячейки QLabel и QLineEdit и Вам надо их заменить на QTableView, TableModel и Delegate - Вам предстоит примерно такой же объем работ. Да, FlyWeightPattern разумно применять вместе с MVC - сначала подумайте, что выделить в модель.

Автор: mes 3.7.2012, 21:21
Цитата(borisbn @  3.7.2012,  07:49 Найти цитируемый пост)
не очень понимаю разницу 

да со статиком в С++ много путаницы.. что касается нашего случая :

статический массив - это массив постоянного размера.. он может располагаться где угодно, не переставая быть от этого  статическим.. 
в С любой массив статический, а динамические массивы  получаются "вручную".. динамический это например стд::вектор... 
память же делится на три категории : статическая, автоматическая и динамическая.. 

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


Добавлено через 2 минуты и 55 секунд
Цитата(borisbn @  3.7.2012,  07:49 Найти цитируемый пост)
Дело в том, что программа изначально не моя, а опенсоурсная.

так что представляет из себя ячейка ? что в ней хранится ? и какие типы операций над ней проводятся ?

Добавлено через 5 минут и 47 секунд
Цитата(math64 @  3.7.2012,  08:15 Найти цитируемый пост)
Для того, чтобы Вы поняли, что такое FlyWeightPattern, приведу реальный пример его использования в Qt - QItemDelegate.

это не совсем то..

Добавлено через 6 минут и 21 секунду
Цитата(math64 @  3.7.2012,  08:15 Найти цитируемый пост)
Пока не вижу другой причины отказа от FlyWeightPattern. 

также как и причин для его применения smile

Добавлено через 8 минут и 7 секунд
Цитата(math64 @  3.7.2012,  07:00 Найти цитируемый пост)
Примеры на C++ применения FlyWeightPattern в описаниях паттерна не очень удачны, 

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

Добавлено через 8 минут и 56 секунд
Цитата(math64 @  2.7.2012,  08:30 Найти цитируемый пост)
. Важно выделить из объекта упакованные данные, по которым всегда можно восстановить объект и тогда объект нужно создавать только тогда, когда он нужен для работы.

ага тут в самую суть  smile 

Автор: mes 3.7.2012, 21:36
Цитата(mes @  3.7.2012,  20:21 Найти цитируемый пост)
 пойду гляну чего там  за примеры..

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

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)