Virtual inheritance and polymorphism: Is the cereal library messing with the layout of the object?

I have four classes ( A , B , C and D ), following the classic diamond pattern and the Container class containing unique_ptr<A> . I want to serialize these classes using the cereal serialization library.

 struct A {int f1; int f2; int f3} struct B : public virtual A { template<typename Archive> inline void save(Archive& ar) const { std::cerr << "Saving Obj: " << this << std::endl; std::cerr << "This: " << &(this->f1) << " " << &(this->f2) << " " << &(this->f3) << std::endl; std::cerr << "This: " << this->f1 << " " << this->f2 << " " << this->f3 << std::endl; }; } }; struct C : public virtual A {}; struct D : public B, public C {}; #include <cereal/archives/binary.hpp> CEREAL_REGISTER_TYPE(B); CEREAL_REGISTER_TYPE(C); CEREAL_REGISTER_TYPE(D); struct Container { std::unique_ptr<A> obj; template<typename Archive> inline void save(Archive& ar) const { std::cerr << "Saving Container" << std::endl; std::cerr << "Obj Addr: " << obj.get() << std::endl; std::cerr << "Obj: " << &(obj->f1) << " " << &(obj->f2) << " " << &(pq->f3) << std::endl; std::cerr << "Obj: " << " " << pq->sq_count << " " << pq->sq_bits << " " << pq->dim << std::endl; ar(obj); // Call serialization for obj, ie B.save(...) } } 

All classes have grain functions save and load , but I have included them only for B and Container , since they are the only ones used in this example.

I use these classes as follows:

 std::unique_ptr<A> obj(new B); obj->f1 = 8; obj->f2 = 8; obj->f3 = 128; std::unique_ptr<Container> db(new Container); db.obj = std::move(obj); std::ofstream out_file(out_filename); cereal::BinaryOutputArchive out_archive(out_file); out_archive(db); 

And I get the following output:

 Saving Container Obj Addr: 0x23d2128 Obj: 0x23d2130 0x23d2134 0x23d2138 // Fields adresses (f1,f2,f3) Obj: 8 8 128 // Fields values Saving Obj: 0x23d2128 // Same object This: 0x23d2118 0x23d211c 0x23d2120 // Different field adresses ! This: 4293296 0 37569440 // Garbage 

My question is: is it possible that this is a mistake in cereals, or is there something that I do not get with virtual inheritance?

Are field addresses of this object expected to ever change in a C ++ program?

+6
source share
1 answer

I can not reproduce your error in the current cereal branch, but I can reproduce it on the current host (1.1.2). I modified your code to actually compile:

 #include <cereal/types/memory.hpp> #include <cereal/types/polymorphic.hpp> #include <cereal/archives/json.hpp> #include <fstream> #include <iostream> struct A { int f1; int f2; int f3; virtual ~A() {} template<typename Archive> void serialize( Archive & ar ) { std::cerr << "Saving A Obj: " << this << std::endl; std::cerr << "This: " << &(this->f1) << " " << &(this->f2) << " " << &(this->f3) << std::endl; std::cerr << "This: " << this->f1 << " " << this->f2 << " " << this->f3 << std::endl; }; }; struct B : public virtual A { template <class Archive> void serialize( Archive & ar ) { std::cerr << "Saving B Obj: " << this << std::endl; std::cerr << "This: " << &(this->f1) << " " << &(this->f2) << " " << &(this->f3) << std::endl; std::cerr << "This: " << this->f1 << " " << this->f2 << " " << this->f3 << std::endl; ar( cereal::virtual_base_class<A>( this ) ); } virtual ~B() {} }; CEREAL_REGISTER_TYPE(B); struct Container { std::unique_ptr<A> obj; template<typename Archive> void serialize( Archive & ar ) { std::cerr << "Saving Container (A)" << std::endl; std::cerr << "Obj Addr: " << obj.get() << std::endl; std::cerr << "Obj: " << &(obj->f1) << " " << &(obj->f2) << " " << &(obj->f3) << std::endl; ar(obj); // Call serialization for obj, ie B.save(...) } }; int main() { std::unique_ptr<A> ptr(new B()); ptr->f1 = 8; ptr->f2 = 8; ptr->f3 = 128; std::unique_ptr<Container> db(new Container()); db->obj = std::move(ptr); std::stringstream ss; { cereal::JSONOutputArchive out_archive(ss); out_archive(db); } std::cout << ss.str() << std::endl; } 

Output from 1.1.2:

 Saving Container (A) Obj Addr: 0x1738d78 Obj: 0x1738d80 0x1738d84 0x1738d88 Saving B Obj: 0x1738d78 This: 0x1738d78 0x1738d7c 0x1738d80 This: 4316664 0 8 Saving A Obj: 0x1738d70 This: 0x1738d78 0x1738d7c 0x1738d80 This: 4316664 0 8 { "value0": { "ptr_wrapper": { "valid": 1, "data": { "value0": { "polymorphic_id": 2147483649, "polymorphic_name": "B", "ptr_wrapper": { "valid": 1, "data": { "value0": {} } } } } } } } 

Output using:

 Saving Container (A) Obj Addr: 0x1f74e18 Obj: 0x1f74e20 0x1f74e24 0x1f74e28 Saving B Obj: 0x1f74e10 This: 0x1f74e20 0x1f74e24 0x1f74e28 This: 8 8 128 Saving A Obj: 0x1f74e18 This: 0x1f74e20 0x1f74e24 0x1f74e28 This: 8 8 128 { "value0": { "ptr_wrapper": { "valid": 1, "data": { "value0": { "polymorphic_id": 2147483649, "polymorphic_name": "B", "ptr_wrapper": { "valid": 1, "data": { "value0": {} } } } } } } } 

Thus, everything that caused this problem was probably fixed in the current growing grain industry, which will be released as 1.2 in the near future.

+1
source

All Articles