Boost logo

Boost :

From: Thorsten Ottosen (nesotto_at_[hidden])
Date: 2004-04-19 20:25:47


Hi Robert,

I have some more stupid questions.

| Thorsten Ottosen wrote:
|
| > Why isn't there a base class for all archieves? I think that would be
| useful
|
| > with class hierachies...for example, I need to implement two function
and
| > cannot use & anymore. Consider this

| I don't understand the need for this. Given that mammal is an abstract
base
| class with no state variables of its own, it needs no serialization at
all.

Ok, but could I have implemented it by having just one function in the
abstract base class which seriaized by calling virtual functions, eg,
name() and age()?

| Just declare it as abstract using BOOST_IS_ABSTRACT(mammal). Only the
| serialization of the derived classes need be specified.

Can BOOST_IS_ABSTRACT be avoided? Maybe some
type-traits can figure this out?

In
struct whale : public mammal
{
    friend class boost::serialization::access;
    whale();
    whale( const std::string& name, unsigned age );
    virtual const std::string& name() const;
    virtual unsigned age() const;
private:
    template<class Archive>
    void serialize(Archive &ar, const unsigned int version){
        ar & boost::serialization::base_object<mammal>(*this);
        ar & name_ & age_ ;
    }
    std::string name_;
    unsigned age_;
};

can the line "ar & boost::serialization::base_object<mammal>( *this )"
be put in a base-class like this

mammal::serialize( Archive& ar, unsigned version )
{
        ar & boost::serialization::base_object<mammal>(*this);
        do_serialize( ar, version ); // virtual function that does the rest
}

to remove some redundancy?

| > I can't figure out exactly how the library save/loads pointers when
these
| > cannot be allocated on the stack.
|
| Please expand some more on this.

I think you explain more about it later. Basically, I couldn't figure out
the scheme with
void*s and cast etc.

| I would love to hear more about this. I would hope that it would easy to
be
| totally successful.

it is now given you showed me how :-) In effect, once the container
supports serialization, a class can be supported in four lines. If you have
not got an example of
class hierarchies, then maybe it should be added.

| > I would like to see the focus shift from vector<T*> towards
| > vector< shared_ptr<T> > and ptr_vector<T>. using T* array[sz] or
| > vector<T*> is inherently unsafe if the pointers are heap-allocated.
|
| I believe that enforcing this is outside my role as a library creator.

ok, but I think you at least should point out very clearly the problems in
it. Some
non-experinced programmer might do what he sees in documentation; therefore
examples should encourage good style.

| 3. const members uses a const-cast to re-init them. AFAICT, this is
| undefined behavior (cmp 7.1.5.1). I guess the need for serialization is
just
| another reason for not having const members.
|
| > this has come up from time to time. I've tried to promote the view that
| > const members shouldn't be serialized but I couldn't convince everyone.
| > I consider it outside my role as a library developer to try to enforce
| > this.

my point was that the examples given give undefined behavior so that
solution
cannot be used.Unless there
is something I overlooked.

| > 4. AFAICR, the use of placement new require proper alignment, so the
| > object must eg. be heap-allocated. Is that guaranteed?
|
| I believe this has been addressed. Objects allocated on the stack use
| aligned storage to handle this.

yes, neat.

| > 6. remove trailing comma in archive_exception.hpp: "unregistered_cast
//
| > base - derived relationship not registered with"
|
| OK - though I don't think its an error.

Comeau call's it non-standard.

| > 8. is_abstract.hpp: there is something wierd about the is_abstact
struct.
| > uncommented the first part to be able to compile.
|
| I don't see this.

// so default to false until the above is really fixed
namespace boost { \
template<class T>
struct is_abstract {
    typedef mpl::false_ type;
    BOOST_STATIC_CONSTANT(bool, value = is_abstract::type::value);
};
} // namespace boost

what is the '\' doing there? I just uncommented the whole thing.

| > 9. serialization/serialization.hpp: why all the static casts?

| > AFAICT, they should be removed. Comeau has the follwing warning: type
| > qualifier is meaningless on cast type
|
| They wouldn't be there except they provide a work around for compilers
which
| do not support Partial Template Function Specialization. On conforming
| compilers, the BOOST_PFTO resolves to nothing so the cast wouldn't be
| necessary. So commeau is correct. I don't know how much effort I want to
| invest to suppress benign warnings for specific compilers.

ok, we should consider either to remove warnings when using bjam or come
up with something.

| > 12. two-phase lookup problems:
| > /boost/archive/basic_text_oarchive.hpp", line 65: error #20:
| > identifier "This" is undefined
| > archive::save(* This(), t);
| ^
| > Solution: prefix base class functions with this->.
|
| I'm not sure I understand this but I don't see it doing any harm. If this
| is a problem, the following would make more sense to me.

when you access something in a dependent base class, Base, one must
prefix function with either this-> or Base::. The first preserves
virtuality, the second
don't. Similarly, typedefs need to be prefixed by Base::.

| archive::save(* common_oarchive<Archive>::This(), t);

the problem is that This() is defined in a dependent base class.

| > 13: archive/text_oarchive.hpp, similar lookup problems.
this->newtoken(),
| > this->delimiter = this->none;
|
| as before - I don't see a problem but changing it doesn't hurt anything.

it makes all the difference on comforming compilers.

| > 14: /archive/detail/basic_iarchive.hpp", line 46: error #20:
| > identifier "basic_iarchive_impl" is undefined
| > boost::scoped_ptr<basic_iarchive_impl> pimpl;
| ^
| >solution: remember to forward declare basic_iarchieve_impl. Do the same
for
| >basic_oarchieve_impl.
|
| OK - I had thought that using friend class made that unnecessary.

I'm not sure who's right here, but at least it will make it work with one
more compiler.

| > 17. when you save_collection_impl.hpp (eg in vector.hpp) there is no
need
| > to specify template arguments again since they will be deduced.
|
| I presume you mean that:
|
| template<class Archive, class U, class Allocator>
| inline void save(
| Archive & ar,
| const std::vector<U, Allocator> &t,
| const unsigned int file_version
| ){
| stl::save_collection<Archive, std::vector<U, Allocator> >(
| ar, t
| );
| }
|
| Can be replaced with:
|
| template<class Archive, class U, class Allocator>
| inline void save(
| Archive & ar,
| const std::vector<U, Allocator> &t,
| const unsigned int file_version
| ){
| stl::save_collection<Archive, std::vector>(
| ar, t
| );
| }

yes.

| But what about:
|
| template<class Archive, class U, class Allocator>
| inline void load(
| Archive & ar,
| std::vector<U, Allocator> &t,
| const unsigned int file_version
| ){
| stl::load_collection<
| Archive,
| std::vector<U, Allocator>,
| stl::archive_input_seq<Archive, std::vector<U, Allocator> >,
| stl::reserve_imp<std::vector<U, Allocator> >
| >(ar, t);
| }
|
| This can't be replaced with:
|
| template<class Archive, class U, class Allocator>
| inline void load(
| Archive & ar,
| std::vector<U, Allocator> &t,
| const unsigned int file_version
| ){
| stl::load_collection<
[snip, correction to no list here]
| >(ar, t);
| }

no, but maybe with this

| stl::archive_input_seq<Archive, std::vector>,
| stl::reserve_imp<std::vector>

by arranging the order of the template parameters.

| Isn't a little bit of redundancy OK giving the alternative of having to
keep
| the details of deducibility in one's brain?

but you already know the types that will be deduced from the outer function.

| > 18. implementation of save_collection(). you cannot use unsigned int
count
| > portably.
|
| I don't see this.
|
| > Instead you should use the new collection traits (reviewed after
| > this review) as follows:
|
| > typename boost::size_type_of< Collection >::type count = size( s );
|
| > then the code will also work for iterator views and arrays. Similar
| > comments apply to load_collection_impl.hpp
|
| I wanted to make the library buildable under 1.31 .

ok, then do

typename Collection::size_type count = s.size();

but don't assume Collection::size_type will be unsigned int.

br

Thorsten


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk