Boost logo

Boost Users :

From: Joaquín Mª López Muñoz (joaquin_at_[hidden])
Date: 2006-09-13 11:40:22


David Abrahams ha escrito:

> Jeff Garland <jeff_at_[hidden]> writes:
>
> > Loïc Joly wrote:
> >> What I meant is that for deserialisation, you still have a two phases
> >> construction: First, build your object with any mean available (if your
> >> object have only constructors with non-default parameters, this will
> >> probably imply building them with dummy parameters), then, in a second
> >> phase, override the member values by the serialized version.
> >
> > Yep.
>
> Nope. Sorry to be blunt, but I just want to make absolutely sure this
> isn't missed:
>
> http://boost.org/libs/serialization/doc/serialization.html#constructors:
>
> template<class Archive>
> inline void load_construct_data(
> Archive & ar, my_class * t, const unsigned int file_version
> ){
> // retrieve data from archive required to construct new instance
> int m;
> ar >> m;
> // invoke inplace constructor to initialize instance of my_class
> ::new(t)my_class(m);
> }
>
> One phase construction.

I am not sure. I'm a little puzzled about the intended purpose of
load_construct_data, as the docs and the code of Boost.Serialization seem to
suggest that it is used for two incompatible tasks:

a) to construct a dummy object prior to deserialization itself, thus
providing a user-overridable hook in case default construction is not
appropriate.
b) to deserialize in place as explained on the bit you quote.

My hunch is that Robert started this with b) in mind but finally the facility
was kept playing a more humble role as a). Consider for instance, serialization
of pointers: currently, if an object instance is saved exclusively through
pointers, Boost.Serialization does the following when the first such
pointer is met

  save_construct_data(ar,p); // S(0)
  ar<<*p; // S(1)

and correspondingly at loading time

  p=get unitialized storage;
  load_construct_data(ar,p); // L(0)
  ar>>*p; // L(1)

By default save_construct_data does nothing and load_construct_data
creates a default cted object, effectively leading to a two-phase construction
scenario. Now, if the user decides to override (save|load)_construct_data
for some class, say foo, so as to perform one-phase construction, we've got
the following:

 S(0) saves foo contents
 S(1) saves foo contents again
 L(0) loads foo contents and creates a foo object with these.
 L(1) loads foo contents again

leading to data duplication within the archive. This can be remedied by
also overriding foo::serialize so as to do nothing, but then foo would be
only serializable through pointers: serialization through instances

  foo f(...)
  ...
  ar<<f;

would do nothing!!

The only way in which load_construct_data would have served purpose b)
is if it had designed so that

1: the default implementation for load_construct_data was:
  load_construct_data(ar,p){
    ::new(p)T();
    ar>>*p;
  }
2: the default implementation for save_construct_data was:
  save_construct_data(ar,p){
    ar<<*p;
  }
3: Through-pointer serialization only consisted of steps S(0) and L(0)
and omitted L(1) and S(1)

With this design, one would be able to override load_construct_data
in the manner explained in serialization.html#constructors while retaining
normal through-instance serializiation. As it currently stands, my view is
that (save|load)_construct_data is not fit for one-phase deserialization.

Am I missing something? I hope Robert has the time to comment on this.

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