[serialization]Can I pass the grandparent class to BOOST_SERIALIZATION_BASE_OBJECT_NVP?

Hi, I'd like to check that my approach is correct or not. Condition: There are three classes A, B and C. The class A is the base class of B. The class B is the base class of C. Requirements: 1.The class A and B shouldn't depend on the serialization library. 2.The class C should be serialized via the base class A (Polymorphic). My approach: Applying non intrusive version serialize function to the class A and B. In the class C, using the macro BOOST_SERIALIZATION_BASE_OBJECT_NVP with the argument A (not B). I skip the class B in the class hierarchy on purpose. If I pass it B instead of A, the following exception would be occurred. "unregistered void cast struct C<-struct A" I believe that my approach is correct. (using A) But I suspect that it might work correctly by accident. #include <boost/serialization/serialization.hpp> #include <boost/archive/xml_oarchive.hpp> #include <boost/archive/xml_iarchive.hpp> #include <boost/serialization/nvp.hpp> #include <boost/serialization/export.hpp> #include <fstream> struct A { virtual ~A() {} }; // non intrusive serialize namespace boost { namespace serialization { template<class Archive> void serialize(Archive& /*ar*/, A&, unsigned int const /*version*/) {} }} struct B : public A {}; // non intrusive serialize namespace boost { namespace serialization { template<class Archive> void serialize(Archive& /*ar*/, B&, unsigned int const /*version*/) {} }} struct C : public B { friend class boost::serialization::access; template<class Archive> void serialize(Archive& ar, unsigned int const /*version*/) { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(A); // My approach // ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(B); } }; BOOST_CLASS_EXPORT(C) int main() { { std::ofstream ofs("test.xml"); C c ; A* a(&c); boost::archive::xml_oarchive oa(ofs); oa << boost::serialization::make_nvp("a", a); } { std::ifstream ifs("test.xml"); boost::archive::xml_iarchive ia(ifs); A* a; ia >> boost::serialization::make_nvp("a", a); assert(dynamic_cast<C*>(a)); delete a; } } Regards, Takatoshi Kondo

Takatoshi Kondo wrote: Hi Takatoshi. Nice hear from you. Havn't heard from you in a while. ... example and expanation in previous post.
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(A); // My approach // ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(B);
If I pass it B instead of A, the following exception would be occurred. "unregistered void cast struct C<-struct A"
Hmmm ... Are sure you don't mean to say "If I pass it A instead of B" One of he side effects of BOOST_SERIALIZATION_BASE_OBJECT_NVP(A) (orB) is to invoke void_cast_register<base class, derived class> ... I would think that you could skip B in this case. But one would have to more carefully investigate how this macro is implemented. Note that if B is implemented as just another macro ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(A); so things can be done the normal way, I would hope that a release build would collapse the code to be equivalent to your method of skipping B. It's also possible the the macro implementation could be refined and/or enhanced to permit the skipping of B if it doesn't do so already. Note that the tests/examples include one case where the void cast register is called directly - thereby eliminating the call to the macro. This short circuits the whole process and would be the most efficient. This is why I believe that the macro could be modified to directly pass A instead of B Robert Ramey

Hi Robert. On Mon, Apr 4, 2011 at 2:44 AM, Robert Ramey <ramey@rrsd.com> wrote:
Hi Takatoshi. Nice hear from you. Havn't heard from you in a while.
Thanks for reply. BTW, I'll attend the boost-con 2011, I'm looking forward to seeing you again :)
... example and expanation in previous post.
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(A); // My approach // ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(B);
If I pass it B instead of A, the following exception would be occurred. "unregistered void cast struct C<-struct A"
Hmmm ... Are sure you don't mean to say "If I pass it A instead of B"
Oh.. I exactly want to say "If I pass it A instead of B". Thanks for your mind-reading :)
One of he side effects of BOOST_SERIALIZATION_BASE_OBJECT_NVP(A) (orB) is to invoke void_cast_register<base class, derived class> ...
My understanding is so.
I would think that you could skip B in this case. But one would have to more carefully investigate how this macro is implemented.
Note that if B is implemented as just another macro ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(A); so things can be done the normal way, I would hope that a release build would collapse the code to be equivalent to your method of skipping B.
Does "collapse" mean to be omitted by optimizer? (Good meaning?)
It's also possible the the macro implementation could be refined and/or enhanced to permit the skipping of B if it doesn't do so already.
Note that the tests/examples include one case where the void cast register is called directly - thereby eliminating the call to the macro. This short circuits the whole process and would be the most efficient. This is why I believe that the macro could be modified to directly pass A instead of B
I checked test_void_cast.cpp. It's very interesting. I can remove the dependency on the serialization library from class A, B and C completely. I can add polymorphic serialization capability later (non intrusively). Amazing! #include <boost/serialization/serialization.hpp> #include <boost/archive/xml_oarchive.hpp> #include <boost/archive/xml_iarchive.hpp> #include <boost/serialization/nvp.hpp> #include <boost/serialization/export.hpp> #include <fstream> // ------------------------------------------------------------------------- struct A { explicit A(int vala_):vala(vala_) {} // pure virtual // to bypass serialize() requirement // If it is non pure, serialize() and default constructor are required. virtual ~A() = 0 {} int vala; }; struct B : public A { B(int vala_, int valb_):A(vala_), valb(valb_) {} int valb; }; struct C : public B { C(int vala_, int valb_, int valc_):B(vala_, valb_), valc(valc_) {} int valc; }; // ------------------------------------------------------------------------- namespace boost { namespace serialization { template<class Archive> void serialize(Archive& /*ar*/, C&, unsigned int const /*version*/) {} template<class Archive> void save_construct_data(Archive& ar, C const* p, unsigned int const /*version*/) { ar << boost::serialization::make_nvp("vala", p->vala); ar << boost::serialization::make_nvp("valb", p->valb); ar << boost::serialization::make_nvp("valc", p->valc); } template<class Archive> void load_construct_data(Archive& ar, C* p, unsigned int const /*version*/) { int a, b, c; ar >> boost::serialization::make_nvp("vala", a); ar >> boost::serialization::make_nvp("valb", b); ar >> boost::serialization::make_nvp("valc", c); ::new(p) C(a, b, c); } }} BOOST_CLASS_EXPORT(C) int main() { { std::ofstream ofs("test.xml"); C c(1, 2, 3); A* a(&c); boost::archive::xml_oarchive oa(ofs); oa << boost::serialization::make_nvp("a", a); } { std::ifstream ifs("test.xml"); boost::archive::xml_iarchive ia(ifs); A* a; ia >> boost::serialization::make_nvp("a", a); C* c = dynamic_cast<C*>(a); assert(c); assert(c->vala == 1); assert(c->valb == 2); assert(c->valc == 3); delete a; } // void_cast_register direct call boost::serialization::void_cast_register<C, A>( static_cast<C *>(NULL), static_cast<A *>(NULL) ); } P.S. I'm in the business trip now. I can't access my primary email account now. This is my second email address. Regards, Takatoshi
participants (3)
-
Robert Ramey
-
Takatoshi Kondo
-
Takatoshi Kondo