2016-02-13 8 views
6

私は古典的な菱形のパターンに続いてを含むContainerクラスの4つのクラス(A,B,CおよびD)を持っています。私はこれらのクラスをcerealシリアライズライブラリを使用してシリアル化したいと思います。バーチャル継承と多型:穀物図書館はオブジェクトレイアウトを乱していますか?

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(...) 
    } 
} 

すべてのクラスは穀物saveload機能を持っていますが、彼らはこの例で使用される唯一のもので、私は唯一、BContainerのためにそれらが含まれています。

次のように私はこれらのクラスを使用します。

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++プログラムでは、特定のオブジェクトのフィールドのアドレスが変更されることはありますか?

+0

なぜ 'ar(obj)'が 'B :: save(ar)'を呼び出すのですか? – aschepler

+0

@ascheplerシリアルライブラリはそれを行います:http://uscilab.github.io/cereal/serialization_functions.html – Xion345

答えて

1

現在の開発中の穀物部門でエラーを再現できませんが、現在のマスター(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": {} 
         } 
        } 
       } 
      } 
     } 
    } 
} 

出力使用しての開発:

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": {} 
         } 
        } 
       } 
      } 
     } 
    } 
} 

をだから、何がこの問題を引き起こしていたことは可能性が固定され近い将来に1.2としてリリースされる穀類の現在の開発枝では、