Boost logo

Boost :

From: Dave Harris (brangdon_at_[hidden])
Date: 2003-10-05 15:55:58

In-Reply-To: <01C38B33.28424310_at_[hidden]>
ramey_at_[hidden] (Robert Ramey) wrote (abridged):
> Looking at it now, (leaving aside the non-portability of reinterpret
> cast)

As David Abrahams says, it is probably better to use void * anyway. My
code was just to convey the basic idea.

> I don't think it adds anything to the system

Well, it solves various problems that have been discussed recently. It
avoids needing a default constructor and/or friend. This is important if
we're to serialise vectors of T without being intrusive. Supporting
std::vector, and not requiring code modifications to serialised classes,
are two of the design goals (6 and 9).

Also, it is simpler to use because load_construct doesn't need to allocate
memory, get the try/catch block right, etc. To me it just seems like the
right separation of concerns.

> and makes it harder to understand and explain. Of course that's a
> subjective assesment so I can't defend it on technical grounds.

Indeed. To me it is a bit simpler. Write load for existing objects, and
load_construct to control how they are created. Passing void * instead of
T * makes the different roles even clearer.

Incidently, this provides an idiom for serialising immutable objects -
write load_construct and not load. I think this could eventually be
developed into something interesting, although I wouldn't want to hold up
the library because of it.

> As I said before my personal preference is that objects never have an
> invalid state. I've found that any thing that uses STL sometimes copies
> things without my being aware of it so its the only way I can have
> confidence that i don't have another obscure bug to find. Havng said
> that, don't think that its a good idea for a serialization package to
> enforce this point of view.

If people want to make the default implementation of load_construct a
friend, so it can use the default constructor, they can do that. Nothing
is being ruled out. However, it does grant some more flexibility.

> the load_construct would still have to gain access to a private default
> constructor so I don't see that it addresses the original concern
> raised by Vladimir.

On the contrary, the point is that load_construct can be overridden by the
user not to use a default constructor. I gave this example:

   template<class Archive>
   void load_construct(Archive & ar, my_class *pt, unsigned int version)
       int a;
       ar >> a;
       new( pt ) my_class( a );
       load( ar, *pt, version );

Load_construct uses a constructor which takes an int, which presumably is
already public. So this lets us serialise my_class without needing to add
a public default constructor, or a private default constructor and
"friend", either of which would mean editing the class's definition.

> template<class Archive ar,>
> void load(Archive & ar, X * &x, unsigned int file_version)
> {
> char *p = NULL;
> try{
> x = new X(ar);
> }
> catch(...){
> delete p;
> throw;
> }
> }
> which would permt the constructor to take the parameters right off the
> top of the archive and avoid any special copying. Someone raised this
> possibility before ( I think it may be you) I sort of dismissed it but
> I believe now that it would be accomodated by the current system by
> means of the above override. It might be of use in certain situations
> where copying the constructor parameters is somehow inconvenient.

I replied to someone else who raised it. At the time I expected there was
some override which would make it work, but I didn't know the library well
enough to say what.

The above is fine, but it doesn't handle the vector case. The standard
library goes to a lot of trouble to define vector such that it does not
need T to be default constructible. I think it is important to carry that
forward to serialisation. (Especially if this library may one day become
part of the standard.)

-- Dave Harris, Nottingham, UK

Boost list run by bdawes at, gregod at, cpdaniel at, john at