Boost logo

Boost :

From: Robert Ramey (ramey_at_[hidden])
Date: 2003-09-29 14:41:16


Vladimir,

I've considered your example in more detail and now feel I can
shed some light on it.

suppose we have:

class A
{
private:
        const m_i;
        A(); // make default unavailable
public:
        A(int i) : m_i(i);
};

What does the following mean?

boost::archive::text_iarchive oa;
A a2(2);
oa << a2;

boost::archive::text_iarchive ia;
A a1(1);
ia >> a1;

should the m_i member variable of a1 equal 2 or should it
equal 1.

In this system it will equal 1 and I think that is correct.
A const member is shouldn't be changed by any operation
(otherwise we wouldn't have made it "const"). The same
argument can be made for any constuctor intialization
arguments - that is that they are part of the "permanent"
state of the object.

On the other hand if we do the following
boost::archive::text_iarchive oa;
A a2(2);
oa << & a2; // serialize as a pointer

boost::archive::text_iarchive ia;
A *a1;
ia >> a1;

then a1.m_i wil be in fact equal to 2 - is this wrong?
I don't think so as we're talking about a new object
as opposed to an already created one whose state
we want to restore.

Moving on to collections of objects.

my current implementation of serialization of
vector<T> clears the vector and for each element
of the vector creates a new one and de-serializes
to fill the contents. Maybe this conflicts with
the discussion above. STL containers elements
are required to implement an assignment operator.
This suggests to me that there is a conceptual
conflict inherent in the idea of an STL container
of objects that require construtor arguments.

Anyway, the answer to your question is

a) the serializations included with the library presume
the existence of a default constructor.

b) If this doesn't apply to your specific case you
can supply your own implementation rather than
use the default one included.

Below is an example of an application which
overrides the default implementation of
of vector serialization. It was the preparation of
this example which raised the questions I posed above.
(This example fails to compile on VC 7.0 due to a compiler
issue - but does compile on gcc).

I believe you were working with gcc 3.3 on linux. Is
this correct? Have you been able to compile and link the
tests. I'm curious about this as my gcc 3.2 cygwin
system doesn't support wide characters and the XML
tests fail on my system.

Robert Ramey

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// test_private_ctor.cpp

// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . Permission to copy,
// use, modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided "as is"
// without express or implied warranty, and with no claim as to its suitability
// for any purpose.

// note: no need to include <boost/serialization/vector.hpp>
// as we're not using the standard version
#include <vector>
#include <sstream>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>

#include <boost/serialization/split_free.hpp>

class A
{
private:
    friend class boost::serialization::access;
    template<class Archive>
    friend void save(
        Archive & ar,
        const std::vector<A> & v,
        const unsigned int version
    );
    A(); // no default constructor available
    const int m_i;
    int m_j;
    template<class Archive>
    void serialize(Archive & ar, unsigned int version){
        ar & m_j;
    }
public:
    A(int i) : m_i(i) {}
    A & operator=(const A & rhs){
        // hmmm - how does m_i get copied?
        // this operation gets invoked when building a vector
        // (at least in VC 7.0 library) but I don't see anyway
        // to implement it !!!
        m_j = rhs.m_j;
        return *this;
    }
    A(const A & rhs) :
        m_i(rhs.m_i),
        m_j(rhs.m_j)
    {
    }
};

template<class Archive>
void save(
    Archive & ar,
    const std::vector<A> & v,
    const unsigned int version
){
    // record number of elements
    unsigned int count = v.size();
    ar << count;
    std::vector<A>::const_iterator it = v.begin();
    while(count-- > 0){
        ar << (*it).m_i;
        ar << *it++;
    }
}

template<class Archive>
void load(
    Archive & ar,
    std::vector<A> & v,
    const unsigned int version
){
    // retrieve number of elements
    unsigned int count;
    ar >> count;
    v.clear();
    v.reserve(count);
    while(count-- > 0){
        int i;
        ar >> i;
        A a(i);
        ar >> a;
        v.push_back(a);
    }
}

BOOST_SERIALIZATION_SPLIT_FREE(std::vector<A>)

int main(){
    std::stringstream ss;
    boost::archive::text_oarchive oa(ss);
    std::vector<A> v;
    A a = A(0);
    v.push_back(a);
    oa << v;
    boost::archive::text_iarchive ia(ss);
    // question? shouldn't the position of ss be reset
    // to 0 here?
    ia >> v;
    return 0;
}


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