2016-02-13 15 views
6

Klasik elmas desenini ve unique_ptr<A> içeren Container sınıfını takip ederek dört sınıfa (A, B, ve D) sahibim. Bu sınıfları cereal serileştirme kitaplığını kullanarak serileştirmek istiyorum.Sanal kalıtım ve polimorfizm: Tahıl kütüphanesi obje düzeni ile uğraşıyor mu?

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

Tüm sınıflar tahıl save ve load işlevlere sahiptir, ancak bu örnekte kullanılan tek olanlar olduğu gibi sadece, B ve Container için onları dahil.

şöyle ben bu sınıfları kullanmak:

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); 

Ve şu çıktıyı almak:

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 

Sorum şu: Bu tahıl bir hata, ya yoktur muhtemelen böyle mi Sanal kalıtımla elde edemediğim bir şey mi?

Belirli bir nesnenin alanlarının adreslerinin bir C++ programında değişmesi bekleniyor mu?

+0

bunu yapar obj 'A'dır. B nereye atlıyor? – Xion345

+0

: tahıl kütüphanesi @aschepler – aschepler

cevap

1

Şu anki geliştirme hububatındaki hatalarınızı yeniden oluşturamıyorum, ancak mevcut master üzerinde yeniden üretebiliyorum (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 ile çıkış

:

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

kullanarak çıkış geliştirmek: Bu soruna neden olan her neyse

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

olasılıkla sabittir Aslında derlemek için kodunuzu modifiye mevcut gelişmekte olan tahıl branşında, yakın gelecekte 1.2 olarak piyasaya sürülecek.