Boost logo

Boost Users :

From: JOAQUIN LOPEZ MU?Z (joaquin_at_[hidden])
Date: 2006-04-03 17:18:14


----- Mensaje original -----
De: John Reid <john.reid_at_[hidden]>
Fecha: Lunes, Abril 3, 2006 5:09 pm
Asunto: Re: [Boost-users] [multi_index] Serialization
problemwithmulti_indexcontainer

> Joaquín Mª López Muñoz wrote:
> > What this means is, if you've got elements a,b and its
corresponding
> > deserialized equivalents a',b', then a<b must yield the same value
> > (true or false) as a'<b' --assuming it is operator< that is used
> for sorting
> > the index, which is the case if identity<element> is the key and
> > the default sorting criterion is used.
>
> Ok thanks, that makes sense. I should have read that.
>
> My value_type has a data member that is a pointer to an object of
> an
> abstract class. I would like one index to be sorted by the
> addresses of these objects.

Yep, here's the problem, addresses' order is not preserved.

> There seems no way to do this and have direct
> serialisation of the multi_index container. Can you confirm?

Yes, I'm afraid you can't directly serialize a multi-index
container one of whose indices is of type ordered_non_unique
and the key is the address of some mmember (or the whole element.)
You'll have to stick to your current workaround --but you
can improve it a bit: you don't really need to use an intermediate
vector if you do the serialization process "by hand":

save:
  save the number of elements.
  traverse the first index and save he visited elements.
load:
  clear the container.
  load the number of elements N.
  repeat N times: load an element and insert it into the container.

The overall effect is the same as with the intermediate vector,
without any extra overhead.

> Maybe I'm
> missing something. Is there a reason why the serialisation
> implementation does not recalculate the indices on the fly?

Well, this is prewisely what's happening. Consider the following:

struct element
{
  element(int x,int y,int z):x(x),y(y),z(z){}
  int x,y,z;
};

typedef multi_index_container<
  element,
  indexed_by<
    ordered_non_unique<member<element,int,&element::x> >,
    ordered_non_unique<member<element,int,&element::y> >
>
> multi_index_t;

multi_index t m;
element a(0,1,0);
element b(1,1,1);
element b(2,1,2);
m.get<1>()insert(a);
m.get<1>().insert(b,m.get<1>().begin());
m.get<1>().insert(c,m.get<1>().begin());

Now, if you traverse m by its index #0, the result is

  (0,1,0), (1,1,1), (2,1,2)

whereas if you traverse it by index #1, the order is,
because of our use of hinted insertion, the following:

  (0,1,0), (2,1,2), (1,1,1)

So far so good. When saving and subsequently loading
this container, Boost.MultiIndex guarantees that the
traversal order of *every* index is preserved. Now,
suppose serialization were implemented the naive way,
that is, by just saving the elements as they are
visited by the first index and loading through the
first index again, just as you're doing in your
workaround (no offense meant by the use of the
word "naive", of course.) If you examine the process
carefully, you can see that, when performed this
way, index #0 is correctly replicated, but the
resulting order of the loaded index #1 is

  (0,1,0), (1,1,1), (2,1,2)

which does not match the original. This is why
Boost.MultiIndex saves, additionally to the elements,
enough extra information to restore index traversal
orders in those cases where such order is not
univocally determined (ordered non-unique,
sequenced and random-access indices.) And when applying
this extra information, the kind of sanity check
you've been bitten by is routinely performed. I
hope I've made myself clear, sorry for the long
explanation.

> Thanks for your response,
> John.

Thank you for using Boost.MultiIndex. I'm sorry
out-of-the-shelf serialization capabilities can't
serve your particular needs.

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net