Russian Qt Forum

Программирование => Общий => Тема начата: Igors от Февраль 11, 2013, 12:24



Название: Resolve Links
Отправлено: Igors от Февраль 11, 2013, 12:24
Добрый день

Есть файл сериализованных данных организованный так

- контейнер объектов класса A
- контейнер объектов класса B
- и.т.д

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

Проблема в том что восстановить указатели немедленно (сразу при чтении) мы не можем (не на что пока указывать, тот объект еще не прочитан). Вопросы к обсуждению

- не надумана ли эта проблема?
- как лучше организовать восстановление указателей?

Спасибо


Название: Re: Resolve Links
Отправлено: Old от Февраль 11, 2013, 12:46
- не надумана ли эта проблема?
Ну как сказать, она довольно просто реализуется

- как лучше организовать восстановление указателей?
Зависит от контейнеров:
* для контейнеров с индексным доступом - вместо указателя сохранять индекс в контейнере. Сохранять строго в той же последовательности, как они хранятся.
* для контейнеров с ключами - сохранять ключ.

После загрузки всех объект, получать указатели объектов по индексу/ключу.


Название: Re: Resolve Links
Отправлено: Igors от Февраль 12, 2013, 12:04
Здесь "контейнер" не значит что сами объекты хранятся в контейнере. Объекты создаются с помощью new, хранится только напр вектор указателей.

Да, вариант с индексом самый естественный/очевидный, именно так у меня и сделано. Вернее, еще тем программистом работу которого я продолжаю, Минус тот что объекты невалидны до тех пор пока ссылки не разрешены.
Код
C++ (Qt)
void A::DoSomething( void )
{
..
if (mData != NULL)   // mData "вообще нет" или "пока нет"?   :-)
..
}
Приходится городить так
Код
C++ (Qt)
class A {
...
int mIndexIO; // да, это поле только для IO, но иначе еще дороже
B * mData;
};
 
Восстановление ссылок также довольно унылая процедура
Код
C++ (Qt)
for (size_t i = 0; i < container_A.size(); ++i)
container_A[i]->ResolveLinks();
 
Ну и уже набежало больше 2 десятков таких циклов.  Вот обдумываю как это улучшить


Название: Re: Resolve Links
Отправлено: Akon от Февраль 12, 2013, 13:17
Сдается мне, вы все ходите вокруг сериализации. А чем boost::serialization не подошел? Избавил бы от многих велосипедов.


Название: Re: Resolve Links
Отправлено: Old от Февраль 12, 2013, 14:18
Здесь "контейнер" не значит что сами объекты хранятся в контейнере. Объекты создаются с помощью new, хранится только напр вектор указателей.
И что это поменяло? Не имеет значения, что хранится в контейнере, сами объекты или указатели на них. От этого их индекс не меняется. :)

Да, вариант с индексом самый естественный/очевидный, именно так у меня и сделано. Вернее, еще тем программистом работу которого я продолжаю, Минус тот что объекты невалидны до тех пор пока ссылки не разрешены.
А у вас в системе этими объектами кто-то может начать пользоваться до завершения их загрузки? Наверное из других потоков.  ;)

Приходится городить так
Код
C++ (Qt)
int mIndexIO; // да, это поле только для IO, но иначе еще дороже
};
 
Повторно сохраняя индекс объекта в контейнере в самом объекте.... Да, вас ждет еще куча проблем впереди. :)


Название: Re: Resolve Links
Отправлено: Igors от Февраль 12, 2013, 14:42
Сдается мне, вы все ходите вокруг сериализации. А чем boost::serialization не подошел? Избавил бы от многих велосипедов.
В стремлении "избежать всяких велосипедов" легко перейти грань и оказаться в роли бездумного пользователя чужих классов. Конечно с бустом этой проблемы не будет - но так будут другие. Напр не потеряю ли я контроль формата файла данных ("архива" по-бустовски)? Так я худо-бедно но могу грузить данные выборочно (напр по ключу), т.к. ID мне известно. А что я буду делать отдав это могучему дусту?

Повторно сохраняя индекс объекта в контейнере в самом объекте.... Да, вас ждет еще куча проблем впереди. :)
Ну так за чем же дело встало? Слушаю Вас как сделать лучше  :)


Название: Re: Resolve Links
Отправлено: Old от Февраль 12, 2013, 15:19
Ну так за чем же дело встало? Слушаю Вас как сделать лучше  :)
Вот смотрите: сейчас этот класс, который вы раньше и сериализовать не думали, должен знать о контейнерах, уметь получать индексы по указателям и наоборот... короче кучу всего, что ему не только уметь делать не надо, а даже знать про это. Я бы воспользовался внешним классом/функцией для сериализации этих объектов. А вот объект этого класса/функция пусть знает про контейнеры, умеет получать индексы и.д., короче читает/пишет эти объекты в поток.
 


Название: Re: Resolve Links
Отправлено: Igors от Февраль 12, 2013, 16:46
Я бы воспользовался внешним классом/функцией для сериализации этих объектов. А вот объект этого класса/функция пусть знает про контейнеры, умеет получать индексы и.д., короче читает/пишет эти объекты в поток.
Прошу исполнить


Название: Re: Resolve Links
Отправлено: Old от Февраль 12, 2013, 16:56
Прошу исполнить

Код
C++ (Qt)
void saveObjectA( ostream &os, const A &obj, const Coll<B*> collB )
{
   os << obj.data1 << obj.data2 << ...;
   os << collB.ptrToIndex( obj.ptrB );
}
 

Эту функцию можно зафрендить с классом А, что бы она имела доступ к закрытым членам.

UPDATE. Я кажется сообразил, что вы хотите посмотреть. :)
При чтении индекс объекта я бы помещал в отдельный контейнер, т.е. указатель в объекте занулили, индекс сохранили во внешней коллекции.
Сразу после завершения процесса чтения, коллекция с индексами разрушиться и все про них забудут. А главное, в рабочих классах не будет никаких "технологических отверстий". :)


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 13:25
Код
C++ (Qt)
void saveObjectA( ostream &os, const A &obj, const Coll<B*> collB )
 
А откуда предположение что нужна именно Coll<B*>? Класс A может ссылаться на объекты любого типа, возможно и базового, поэтому делать общий доступ ко всем коллекциям сериализации придется, напр
Код
C++ (Qt)
template <class T>
const Coll<T *> & GetCollOfType( const T & );
 

UPDATE. Я кажется сообразил, что вы хотите посмотреть. :)
При чтении индекс объекта я бы помещал в отдельный контейнер, т.е. указатель в объекте занулили, индекс сохранили во внешней коллекции.
Из этого неясно как же Вы собирались реализовать чтение. Ну получили контейнер индексов, как потом их присобачить к объектам на фазе resolve?


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 13:43
А откуда предположение что нужна именно Coll<B*>? Класс A может ссылаться на объекты любого типа, возможно и базового, поэтому делать общий доступ ко всем коллекциям сериализации придется, напр
Пожалуйста. Как вам будет удобней. :)

Из этого неясно как же Вы собирались реализовать чтение. Ну получили контейнер индексов, как потом их присобачить к объектам на фазе resolve?
Ну примитивная же задача. Не придумаете, я вечером выложу код с комментариями. Сейчас не могу, убегаю.



Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 13:46
Ну примитивная же задача. Не придумаете, я вечером выложу код с комментариями. Сейчас не могу, убегаю.
Конечно, не горит. А как у меня сделано я уже показал (доп поле данных)


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 16:49
А как у меня сделано я уже показал (доп поле данных)

Внимание!!! Это просто набросок! :)

Пытаемся избавится от доп полей, для этого используем коллекцию для сохранения индексов объектов.
Код
C++ (Qt)
// Функция верхнего уровня для загрузки данных
bool loadFile( ... )
{
   ifstream is;
   ...
   int version;
   is >> version;
 
   int numObjA;
   is >> numObjA;
 
   std::deque<ClassA *> collA( numObjA );
   std::deque<int> idxCollA( numObjA );
 
   for( int i = 0; i < numObjA; ++i )
   {
       int idx;
       ClassA *o = new ClassA;
       readObjectA( is, o, idx );
       collA[ i ] = o;
       idxCollA[ i ] = idx;
   }
 
   int numObjB;
   is >> numObjB;
 
   std::deque<ClassB *> collB( numObjB );
 
   for( int i = 0; i < numObjB; ++i )
   {
       ClassB *o = new ClassB;
       readObjectB( is, o, collA );    // Здесь мы уже можем резолвить указатели на объекты из контейнера А
       collA[ i ] = o;
   }
 
   // Резолвим индексы объектов из контейнера А.
   for( int i = 0; i < numObjA; ++i )
   {
       collA[ i ]->ptrB = collB[ idxCollA[ i ] ];
   }
}
 
void readObjectA( istream &is, A &obj, int &idx )
{
   is >> obj.data1 >> obj.data2 >> ...;
   is >> idx;  // Читаем индекс объекта для связи в контейнере B.
}
 

Писал прямо здесь.
Для коллекций не поддерживающих последовательный доступ пример переделывается элементарно.


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 17:26
Внимание!!! Это просто набросок! :)
Ладно, "на взлете бить не буду" :) По существу: а почему Вы исходите из предположения что только класс A ссылается только на класс B и имеет строго 1 ссылку (указатель)?  Не наивно ли такое проектирование?  :)

[/offtop]
На форуме много молодых людей которые много, ну очень много, знают. Более того, они стремятся знать все больше и больше. Ну у каждого свой подход. Я не стремлюсь знать больше, но мне интересно "как сделать конструкцию лучше", я люблю в этом копаться. Если Вам нет - я не хочу тратить Ваше время


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 17:41
Ладно, "на взлете бить не буду" :)
Конечно не будете. Бить то нечем. Если вы перечитаете всю тему и посмотрите "свои наброски" с mIndex, то поймете, что у вас точно такойже функционал, только с большими ограничениями. :)
Вы предлагаете условия, а мы по ним играем... Не так ли?

но мне интересно "как сделать конструкцию лучше", я люблю в этом копаться. Если Вам нет - я не хочу тратить Ваше время
Не похоже. :)


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 18:15
Вы предлагаете условия, а мы по ним играем... Не так ли?
Почему "условия"? Я показал, как сделал я, да, член данных "только для IO" конечно не украшает, но по-моему это оптимальное решение. Предлагайте лучше - с удовольствием послушаю.

Если вы перечитаете всю тему и посмотрите "свои наброски" с mIndex, то поймете, что у вас точно такойже функционал, только с большими ограничениями. :)
Да чего же с "большими" когда совсем наоборот ??? Я поддерживаю resolve указателей любого типа, а у Вас (во всяком случае пока) "детский сад" (A ссылается на B, а остальное хоть трава не расти).


Название: Re: Resolve Links
Отправлено: Bepec от Февраль 13, 2013, 18:41
Igors возьмите за пример OPC технологию если хотите.

Имеются ноды, взаимосвязанные между собой. Каждая нода может иметь n+1 связей с другими нодами. Каждая нода может содержать в себе n+1 объектов различных типов. Ноды не индексируются, а подгружаются по мере необходимости. Каждая нода имеет уникальный идентификатор, до трёх различных типов (гуид, число, строка). Соответственно получается этакая паутина. Да, нода может иметь, может не иметь объекты. Каждая нода может быть привязана к данных, а может являться индексом для других нод :D

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

PS к сожалению особые тонкости реализации не подскажу и не расскажу. А то голову оторвут :D Полтора ляма всё таки библиотечка :)


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 19:08
PS к сожалению особые тонкости реализации не подскажу и не расскажу. А то голову оторвут :D Полтора ляма всё таки библиотечка :)
Ну почему же "к сожалению"? Пацаны предложили свои решения в теории графов и сняли за это бабки - 100% заслуженно, молодцы! Но тут такой глобвльной задачи не стоит - нужно только восстановить зависимости (т.е. "ребра" графа) а насколько он корректен и что с ним делать - то уже др вопрос


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 19:17
Почему "условия"? Я показал, как сделал я, да, член данных "только для IO" конечно не украшает, но по-моему это оптимальное решение. Предлагайте лучше - с удовольствием послушаю.
Вот выше я вам и привел набросок решения, которое избавляет ваш класс от совершенно ненужного ему члена. :)
Вы не разобрались? Ах да, я обещал много комментариев и не привел их.

Да чего же с "большими" когда совсем наоборот ??? Я поддерживаю resolve указателей любого типа, а у Вас (во всяком случае пока) "детский сад" (A ссылается на B, а остальное хоть трава не расти).
Вы вначале разберитесь. Мой пример делает ровно тоже, что и ваш, кроме того, что не хранит ненужные члены внутри каждого объекта класса. Вот где настоящий детский сад. И он так же поддерживает указатели на любые типы. :)

В общем все как здесь:  ;D
Код
C++ (Qt)
int mIndexIO;
};
 


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 19:29
Вот выше я вам и привел набросок решения, которое избавляет ваш класс от совершенно ненужного ему члена. :)
Вы не разобрались? Ах да, я обещал много комментариев и не привел их.
Ну а "брать на понт" зачем? :) Пусть экземпляр A ссылается на др A (а не на B). Или вообще на базовый класс для A и B? Как тогда отработает Ваш вариант?


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 19:31
Ну а "брать на понт" зачем? :) Пусть экземпляр A ссылается на др A (а не на B). Или вообще на базовый класс для A и B? Как тогда отработает Ваш вариант?
А давайте так. Вы выкладываете сюда свой вариант с супер-членом, а я его переделаю на хранение во внешней коллекции. Так сказать спасу эти классы от "технологических отверстий". :)

А то у вас этот супер-индекс, сам разбирается на что указывает указатель... Вот какой талантливый int. :)


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 19:48
А давайте так. Вы выкладываете сюда свой вариант с супер-членом, а я его переделаю на хранение во внешней коллекции. Так сказать спасу эти классы от "технологических отверстий". :)
Ну мне прилагать какие-то усилия (по выкладке Вам проекта и др) как-то неинтересно если с Вашей стороны заверения подтверждаются только наивным кодом - и ничем более

А то у вас этот супер-индекс, сам разбирается на что указывает указатель... Вот какой талантливый int. :)
Да ну, сказали такое  :) Тип-то есть, пусть базовый. Индекс тоже на руках - дальше дело несложной техники. А вот если вынести индекс - тонна геморроя. Или не так?

P.S. Не злитесь  :)


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 19:49
Ну мне прилагать какие-то усилия (по выкладке Вам проекта и др) как-то неинтересно если с Вашей стороны заверения подтверждаются только наивным кодом - и ничем более
Другого ответа я и не ожидал. :)

А вот если вынести индекс - тонна геморроя.
Опять пустые слова.
Ну да ладно... :)


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 19:50
Опять пустые слова.
У кого?  :)


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 19:52
У кого?  :)
У вас. Кода нет, одни "А вот если, то ... ". Там сложно, здесь не возможно... Бла бла бла :)


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 20:04
У вас. Кода нет, одни "А вот если, то ... ". Там сложно, здесь не возможно... Бла бла бла :)
Я структуру данных показал - из нее все очевидно. Да, пусть с минусами - ну редко работающий член. А у Вас вроде все "элементарно" - да только на словах, а до дела доходит -  рассыпается как карточный домик  :)


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 20:09
Я структуру данных показал - из нее все очевидно. Да, пусть с минусами - ну редко работающий член. А у Вас вроде все "элементарно" - да только на словах, а до дела доходит -  рассыпается как карточный домик  :)
С какими минусами? Она не может работать. Еще раз, int не сможет сохранить информацию о контейнере, в котором хранится объект. Значит, это требование вы как всегда "высосали из пальца" только что.
Ну и что нам спорить, давайте ваш код? А я его исправлю. Или слабо это даже показать? :)
Ась?


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 20:27
Ну и что нам спорить, давайте ваш код? А я его исправлю. Или слабо это даже показать? :)
Ась?
Так это запросто
Код
C++ (Qt)
void A::ResolveLinks( void )
{
 mPtrB = GetCollection<B>()[mIndexIO_B];
 mPtrC = GetCollection<C>()[mIndexIO_C];
...
}
 
Какие проблемы? Чем плохо?


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 20:31
Какие проблемы? Чем плохо?
Ну так, а какие проблемы:
Код
C++ (Qt)
   for( int i = 0; i < numObjA; ++i )
   {
       collA[ i ]->ptrB = GetCollection<B>()[ idxCollA[ i ] ];
   }
 


Название: Re: Resolve Links
Отправлено: Igors от Февраль 13, 2013, 20:48
Ну так, а какие проблемы:
Код
C++ (Qt)
   for( int i = 0; i < numObjA; ++i )
   {
       collA[ i ]->ptrB = GetCollection<B>()[ idxCollA[ i ] ];
   }
 
Ну блин, сравнили палец с <template>. У меня-то все в теле A, он прекрасно знает какие члены резолвить (любое число). А у Вас посторонка которая сует хобот во все подробности A и которую все время надо латать. А если A - базовый для B - то просто рухнет


Название: Re: Resolve Links
Отправлено: Old от Февраль 13, 2013, 20:52
Ну блин, сравнили палец с <template>.
Вот именно. :)
В классе А куча всего, чего ему знать не надо, но вы его усиленно пытаетесь этому научить. Он у вас завязан на все коллекции, на все классы... Это конечно хуже одного посредника.
Код покажите свой, а я его исправлю и сравним. ;)

А если A - базовый для B - то просто рухнет
Не придумывайте.  ;)


Название: Re: Resolve Links
Отправлено: Igors от Февраль 14, 2013, 11:53
Если делать в общем виде, то может так
Код
C++ (Qt)
struct CDescriptorIO {
size_t mIndex;  // индекс
int mType;   // тип (для полиморфных)
};
 
void readObjectA( istream &is, A &obj, vector <CDescriptorIO> & desc )
{
   is >> obj.data1 >> obj.data2 >> ...;
   desc.clear();
   desc.push_back(CDescriptorIO());
   is >> desc.back().mIndex;
   ..
}
А при resolve объект опять получает вектор который сам заполнил и может восстановить указатели. Можно добавить в дескриптор и указатель на объект который заполнит пресловутый посредник. Возможна и более вызывающая реализация
Код
C++ (Qt)
size_t temp;
is >> temp;
obj.mPtrB = (B *) temp;
 
Без доп полей.

В классе А куча всего, чего ему знать не надо, но вы его усиленно пытаетесь этому научить. Он у вас завязан на все коллекции, на все классы... Это конечно хуже одного посредника.
Неубедительно. Если A держит указатель на B, значит хедер B он уже видит - не вижу какие новые зависимости возникают


Название: Re: Resolve Links
Отправлено: Old от Февраль 14, 2013, 14:02
Если делать в общем виде, то может так
Фух, ну слава Богу. Дааа, как-то вы не быстро соображаете. :)

Неубедительно.
Забейте. Это уже не важно. :)

Возможна и более вызывающая реализация
Код
C++ (Qt)
size_t temp;
is >> temp;
obj.mPtrB = (B *) temp;
 
Без доп полей.
Да, прямо вызывающая. :)
А вообще есть union. Ну а что? :)