虚拟继承和多态性:谷物库是否扰乱了对象布局?
Virtual inheritance and polymorphism: Is the cereal library messing with object layout?
我有四个 classes(A
、B
、C
和 D
)遵循 classic 菱形图案和一个 Container
class 包含一个 unique_ptr<A>
。我想使用 cereal 序列化库序列化这些 classes。
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(...)
}
}
所有 classes 都有谷物 save
和 load
功能,但我只为 B
和 Container
添加了它们,因为它们是唯一的本例中使用的那些。
我使用这些 classes 如下:
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);
我得到以下输出:
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
我的问题是:这可能是谷类食品中的错误,还是我无法通过虚拟继承获得某些东西?
给定对象的字段地址是否会在 C++ 程序中发生变化?
我无法在当前的 cereal 开发分支上重现您的错误,但是我可以在当前的 master (1.1.2) 上重现它。我修改了你的代码以实际编译:
#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;
}
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": {}
}
}
}
}
}
}
}
使用 develop 的输出:
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": {}
}
}
}
}
}
}
}
因此,导致此问题的原因很可能已在 cereal 的当前开发分支中修复,该分支将在不久的将来发布为 1.2。
我有四个 classes(A
、B
、C
和 D
)遵循 classic 菱形图案和一个 Container
class 包含一个 unique_ptr<A>
。我想使用 cereal 序列化库序列化这些 classes。
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(...)
}
}
所有 classes 都有谷物 save
和 load
功能,但我只为 B
和 Container
添加了它们,因为它们是唯一的本例中使用的那些。
我使用这些 classes 如下:
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);
我得到以下输出:
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
我的问题是:这可能是谷类食品中的错误,还是我无法通过虚拟继承获得某些东西?
给定对象的字段地址是否会在 C++ 程序中发生变化?
我无法在当前的 cereal 开发分支上重现您的错误,但是我可以在当前的 master (1.1.2) 上重现它。我修改了你的代码以实际编译:
#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;
}
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": {}
}
}
}
}
}
}
}
使用 develop 的输出:
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": {}
}
}
}
}
}
}
}
因此,导致此问题的原因很可能已在 cereal 的当前开发分支中修复,该分支将在不久的将来发布为 1.2。