Problems using boost serializing and custom constructors

Hi I'm trying to use boost::serialize for the first time, but I have some troubles figuring out how to serialize a class like this: #include <vector> struct Foo { struct Bar { std::vector<int> * data; // Must point to Foo::data Bar( std::vector<int> * d ) : data(d) { } }; std::vector<int> data; std::vector<Bar> elements; Foo() { // do very time consuming calculation to populate "data" and "elements" } }; Here is what I have tried: struct Foo { struct Bar { std::vector<int> * data; Bar( ) : data( 0 ) { } Bar( std::vector<int> * d ) : data(d) { } template<class Archive> void serialize(Archive & ar, const unsigned int version) { ar & data; // is this correct? } }; std::vector<int> data; std::vector<Bar> elements; Foo() { std::cerr << "Running default constructor" << std::endl; data.push_back(1); data.push_back(2); data.push_back(3); data.push_back(4); data.push_back(5); elements.push_back( Bar( &data ) ); elements.push_back( Bar( &data ) ); elements.push_back( Bar( &data ) ); } template<class Archive> Foo( Archive & ar ) { ar >> data; // is this corrent? ar >> elements; } private: BOOST_SERIALIZATION_SPLIT_MEMBER(); friend class boost::serialization::access; template<class Archive> void save(Archive & ar, const unsigned int version) const { const std::vector<int> * data_ptr = &data; // should data be seriliazed as pointer... // it is used as a pointer in Bar ar << data_ptr; ar << elements; } }; int main(int argc, const char *argv[]) { #if 0 // serialize Foo foo; boost::archive::text_oarchive oar(std::cout); oar << foo; #else // deserialize boost::archive::text_iarchive oar(std::cin); Foo foo(oar); #endif std::cerr << foo.data.size() << std::endl; std::cerr << foo.elements.size() << std::endl; std::cerr << (&foo.data) << std::endl; for( const auto& a : foo.data ) std::cerr << a << " "; std::cerr << std::endl; for( const auto& a : foo.elements) std::cerr << a.data << " "; std::cerr << std::endl; return 0; } The only problem is that it does not work. After I deserialize Foo, data is still empty. Please advise me on how to do this properly. Best regards Allan W. Nieslen

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi! Am 06.03.12 15:58, schrieb Allan Nielsen:
std::vector<int> data; std::vector<Bar> elements;
Foo() { // do very time consuming calculation to populate "data" and "elements" } };
Consider a change in design: make Foo default constructible and provide a static factory method to populate data and elements: struct Foo { ... Foo() {} // empty members static Foo createWithData() { Foo result; // do very time consuming calculation to // populate "data" and "elements" return result; // will move, not copy data in C++11 } }; The Foo(Archive&) approach will not scale well because I guess proper serialization of Foo will only be possible through a pointer (which implies the object will be constructed on the heap on deserialization.) For serialization through a pointer there is a way to use a non-default constructor as described here: http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/serialization.ht...
Here is what I have tried:
struct Foo { struct Bar { std::vector<int> * data;
Bar( ) : data( 0 ) { } Bar( std::vector<int> * d ) : data(d) { }
template<class Archive> void serialize(Archive & ar, const unsigned int version) { ar & data; // is this correct?
This looks good with the changes in Foo::serialize.
} };
std::vector<int> data; std::vector<Bar> elements;
Foo() { std::cerr << "Running default constructor" << std::endl; data.push_back(1); data.push_back(2); data.push_back(3); data.push_back(4); data.push_back(5); elements.push_back( Bar( &data ) ); elements.push_back( Bar( &data ) ); elements.push_back( Bar( &data ) ); }
template<class Archive> Foo( Archive & ar ) { ar >> data; // is this corrent?
It does not match the save operation: saving a pointer and loading a reference does not match. This is not correct.
ar >> elements; }
private: BOOST_SERIALIZATION_SPLIT_MEMBER(); friend class boost::serialization::access;
template<class Archive> void save(Archive & ar, const unsigned int version) const { const std::vector<int> * data_ptr = &data;
// should data be seriliazed as pointer... // it is used as a pointer in Bar ar << data_ptr; ar << elements; } };
My proposal: do not split into load/save, use the following instead: template<typename Archive> void serialize(Archive &ar, const unsigned int) { auto * data_ptr = &data; ar & data_ptr; // load and save through pointer if(Archive::is_loading::value) { data = std::move(*data_ptr); // no-throw ar.reset_object_address(&data, data_ptr); delete data_ptr; // not sure here } // load elements after reset_object_address() ar & elements; } The alternative is to make data a non-std type, like make a custom struct of it. Then you could just use ar & data & elements in combination with boost::serialization::track_always. http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/special.html#obj... HTH, Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.17 (Darwin) Comment: GPGTools - http://gpgtools.org Comment: keyserver x-hkp://pool.sks-keyservers.net iEYEARECAAYFAk9WhVEACgkQhAOUmAZhnmpFmACfRD1fVPfgrrkEYZpNlOzbi5VS 2EQAn0dHsN3U3FxV/9Wc0TMe2ESy5fWP =zdeg -----END PGP SIGNATURE-----

Hi again, I have now tried to get your suggested solution to work, but did not succeed.
template<typename Archive> void serialize(Archive &ar, const unsigned int) { auto * data_ptr = &data; ar & data_ptr; // load and save through pointer
if(Archive::is_loading::value) { data = std::move(*data_ptr); // no-throw ar.reset_object_address(&data, data_ptr); delete data_ptr; // not sure here }
This produced a compiler error, so I slitted it into separated load and save methods which looks like this: BOOST_SERIALIZATION_SPLIT_MEMBER(); template<class Archive> void save(Archive & ar, const unsigned int version) const { const std::vector<unsigned> * data_ptr = &data; ar & data_ptr; // load and save through pointer } template<class Archive> void load(Archive & ar, const unsigned int version) { const vector<int> * data_ptr; ar & data_ptr; // load and save through pointer data = std::move(*data_ptr); // no-throw ar.reset_object_address(&data, data_ptr); delete data_ptr; } But unfortunately, when I loads all the remaining pointers to data, the pointers has not been reset. This make me think the "ar.reset_object_address(&data, data_ptr);" method does not work properly ( I have ensured that it is executed before the loads ). Also, if I add: BOOST_STATIC_ASSERT( (boost::serialization::tracking_level< const std::vector<unsigned> * >::value != boost::serialization::track_never) ); I get an compiler error saying static assert failed. Why is that? shouldn't everything serialized through a pointer be tracked? What can I do to fix this? Best regards Allan W. Nielsen

Allan Nielsen wrote:
Hi again,
I have now tried to get your suggested solution to work, but did not succeed.
template<typename Archive> void serialize(Archive &ar, const unsigned int) { auto * data_ptr = &data; ar & data_ptr; // load and save through pointer
if(Archive::is_loading::value) { data = std::move(*data_ptr); // no-throw ar.reset_object_address(&data, data_ptr); delete data_ptr; // not sure here }
This produced a compiler error, so I slitted it into separated load and save methods which looks like this:
BOOST_SERIALIZATION_SPLIT_MEMBER();
template<class Archive> void save(Archive & ar, const unsigned int version) const { const std::vector<unsigned> * data_ptr = &data; ar & data_ptr; // load and save through pointer }
template<class Archive> void load(Archive & ar, const unsigned int version) { const vector<int> * data_ptr; ar & data_ptr; // load and save through pointer data = std::move(*data_ptr); // no-throw ar.reset_object_address(&data, data_ptr); delete data_ptr; }
This whole thing looks a little suspicious to me. I'd have to spend considerable time looking into it. But I'm curious why you don't just do the following: template<class Archive> void save(Archive &ar, const unsigned int version) const { ar << data; } template<class Archive> void load(Archive &ar, const unsigned int version){ ar >> data; }
Also, if I add:
BOOST_STATIC_ASSERT( (boost::serialization::tracking_level< const std::vector<unsigned> * >::value != boost::serialization::track_never) );
I get an compiler error saying static assert failed. Why is that? shouldn't everything serialized through a pointer be tracked?
again, I'd have to look into this more deeply. I'm a little intriqued with serilization of
const vector<int> * data_ptr;
I guess it's ok but it's sort of wierd to load a pointer to a CONST. Robert Ramey
What can I do to fix this?
Best regards Allan W. Nielsen _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Hi
This whole thing looks a little suspicious to me. Well, it is most likely because I;m doing it completely wrong ;) Please correct me.
I'd have to spend considerable time looking into it. But I'm curious why you don't just do the following:
template<class Archive> void save(Archive &ar, const unsigned int version) const { ar << data; }
template<class Archive> void load(Archive &ar, const unsigned int version){ ar >> data; }
Because I have a shared pointer, and ( for other reasons ) I do not want to use "shared_ptr" So, a simplified version of my problem could look like this: struct A { std::vector<unsigned> data; }; struct B { const std::vector<unsigned> * data_ptr; }; struct C { A a; std::vector<B> elements; }; What would a serializing function for A, B and C look like. Best regards Allan W. Nielsen

Allan Nielsen wrote:
Hi
This whole thing looks a little suspicious to me. Well, it is most likely because I;m doing it completely wrong ;) Please correct me.
I'd have to spend considerable time looking into it. But I'm curious why you don't just do the following:
template<class Archive> void save(Archive &ar, const unsigned int version) const { ar << data; }
template<class Archive> void load(Archive &ar, const unsigned int version){ ar >> data; }
Because I have a shared pointer, and ( for other reasons ) I do not want to use "shared_ptr"
hmmm- I assume you are aware that you can serialize a shared_ptr.
So, a simplified version of my problem could look like this:
struct A { std::vector<unsigned> data; };
struct B { const std::vector<unsigned> * data_ptr; };
struct C { A a; std::vector<B> elements; };
What would a serializing function for A, B and C look like.
// external version template<class Archive> void serialize(Archive &ar, A & a, const unsigned int version){ ar & data;; } template<class Archive> void serialize(Archive &ar, B & b, const unsigned int version){ ar & data_ptr;; } template<class Archive> void serialize(Archive &ar, C & c, const unsigned int version){ ar & a; ar & elements; } Robert Ramey
Best regards Allan W. Nielsen _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi! Am 12.03.12 22:05, schrieb Robert Ramey:
template<class Archive> void serialize(Archive &ar, A & a, const unsigned int version){ ar & data;; }
When first serializing through a reference, how come that the vector instance is tracked? Is every object tracked by default? I do not understand the magic behind selective tracking. Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.17 (Darwin) Comment: GPGTools - http://gpgtools.org Comment: keyserver x-hkp://pool.sks-keyservers.net iEYEARECAAYFAk9e5PEACgkQhAOUmAZhnmqVgwCeKXKBt/yZN4OL1OlAT9mVHKIs Q4UAn0fhGf/whLhV2Ncwnlp4WZzQpAqb =3Eql -----END PGP SIGNATURE-----

Hi,
When first serializing through a reference, how come that the vector instance is tracked? Is every object tracked by default? I do not understand the magic behind selective tracking.
I do not understand this either. There is only suppose to exist one copy of "data" in the serialized data. Best regards Allan W. Nielsen

Hi again,
I have now created a small run able program which illustrates the
problem I'm having:
#include

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi! Am 13.03.12 20:39, schrieb Robert Ramey:
I posted a example - did this not work?
It worked for me using Boost 1.47. The code below can output or input
serialization data. It links to Boost.Serialization of course. I
tested it by running it twice and piping the output of the first into
the input of the second instance:
$dist/test 1 | dist/test 2
1
Frank
///// Main.cpp:
#include <vector>
struct A {
std::vector<unsigned> data;
};
struct B {
const std::vector<unsigned> * data_ptr;
};
struct C {
A a;
std::vector<B> elements;
};
template<class Archive>
void serialize(Archive &ar, A & a, const unsigned int version){
ar & a.data;
}
template<class Archive>
void serialize(Archive &ar, B & b, const unsigned int version){
ar & b.data_ptr;
}
template<class Archive>
void serialize(Archive &ar, C & c, const unsigned int version){
ar & c.a;
ar & c.elements;
}
struct Sample {
Sample();
C const& getC() { return c; }
C c;
} sample;
Sample::Sample()
{
c.a.data.push_back(5);
const B b = { &c.a.data };
c.elements.resize(2, b);
}
#include

Hi Robert
I posted a example - did this not work?
I did look at you example, but I did not understand how it could possibly work. And therefor for I did not try it out as the first thing. However, I have tried it now, and it is working. The only problem is that I do not understand how. Also, I do not understand why the (not so elegant) example of mine, does not work... But anyway, thanks for providing a good solution to my problem. Best regards Allan W. Nielsen

Allan Nielsen wrote:
Hi Robert
I posted a example - did this not work?
I did look at you example, but I did not understand how it could possibly work. And therefor for I did not try it out as the first thing.
However, I have tried it now, and it is working. The only problem is that I do not understand how.
Basically, if a) you've installed boost b) read the documentation for the serialization library c) and it's not clear why my code works then It's a bug in the documentation. As far as I'm concerned this is the same as a bug in the code they really are "one thing". So, if you go back the documentation, I believe you should be able to discover why my example works. If you do this and conclude that something needs to be added to the documentation feel free to propose some more language the documentation which would avoided the confusion. Then post this is a trac item and it will eventually make it's way into the official documentation. This will give you a constructive way to vent your frustration and avoid having another person suffer this same fate.
Also, I do not understand why the (not so elegant) example of mine, does not work...
Honestly, I couldn't really understand your example without investing a lot more effort. But if you do the above, you will likely be able to understand this yourself.
But anyway, thanks for providing a good solution to my problem.
My pleasure Robert Ramey
participants (3)
-
Allan Nielsen
-
Frank Birbacher
-
Robert Ramey