Ok so I'm running into a problem in C++11 with cereal (http://ift.tt/1jDSDLg).
In an abstract sense I have a large graph which I am serializing with lots of shared pointers connecting the edges and vertices. Edges (and vertices) also have attributes attached to them.
Now one of these attributes (base class) is an account (child class). Account also inherits from Idable which also is serializable. Now here are some pertinent snips of code which show some of my cereal usage. I'll explain the issue after this context:
Attribute.hpp/cpp
class Attribute {
...
template<class Archive> void serialize(Archive&)
{
}
friend class cereal::access;
...
CEREAL_REGISTER_TYPE(mgraph::Attribute)
Idable.hpp/cpp
class Idable {
...
Id id;
template<class Archive> void serialize(Archive& archive)
{
archive(cereal::make_nvp("id", id));
}
template<class Archive> static void load_and_construct(Archive& ar, cereal::construct<mcommon::Idable>& construct)
{
mcommon::Id id;
ar(id);
construct(id);
}
friend class cereal::access;
...
CEREAL_REGISTER_TYPE(mcommon::Idable)
Position.hpp/cpp
class Position
: public mgraph::Attribute
, public mcommon::Displayable {
template<class Archive> void serialize(Archive& archive)
{
archive(cereal::make_nvp("Attribute",
cereal::base_class<mgraph::Attribute>(this)));
}
friend class cereal::access;
...
CEREAL_REGISTER_TYPE(mfin::Position)
Account.hpp/cpp
class Account
: public mcommon::Idable
, public Position {
...
Currency balance;
template<class Archive> void serialize(Archive& archive)
{
archive(cereal::make_nvp("Idable",
cereal::base_class<mcommon::Idable>(this)),
cereal::make_nvp("Position",
cereal::base_class<mfin::Position>(this)),
cereal::make_nvp("balance", balance));
}
template<class Archive> static void load_and_construct(Archive& ar, cereal::construct<Account>& construct)
{
mcommon::Id iden;
Currency::Code code;
ar(iden, code);
construct(iden, code);
}
friend class cereal::access;
...
CEREAL_REGISTER_TYPE(mfin::Account)
So the problem comes when a mfin::Account is being serialized. The mfin::Account belongs to a std::list>. When we get down into the serialize function for Idable the object is invalid.
Going into gdb which halts on a segfault I go up a few stackframes to this this line: /usr/include/cereal/types/polymorphic.hpp:341. Which is:
(gdb) list
336
337 auto binding = bindingMap.find(std::type_index(ptrinfo));
338 if(binding == bindingMap.end())
339 UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name()))
340
341 binding->second.shared_ptr(&ar, ptr.get());
342 }
343
344 //! Loading std::shared_ptr for polymorphic types
345 template <class Archive, class T> inline
Now here this is what ptr is:
(gdb) print *((mfin::Account*)(ptr.get()))
$10 = {<mcommon::Idable> = {_vptr.Idable = 0x4f0d50 <vtable for mfin::Account+16>, id = "bank"}, <mfin::Position> = {<mgraph::Attribute> = {
_vptr.Attribute = 0x4f0d78 <vtable for mfin::Account+56>}, <mcommon::Displayable> = {_vptr.Displayable = 0x4f0da0 <vtable for mfin::Account+96>}, <No data fields>}, balance = {<mcommon::Displayable> = {
_vptr.Displayable = 0x4f0570 <vtable for mfin::Currency+16>}, amount = 0, code = mfin::Currency::USD}}
(gdb) print ptr
$11 = std::shared_ptr (count 3, weak 0) 0x758ad0
Everything is looking good. But notice when I cast it to a void*:
$11 = std::shared_ptr (count 3, weak 0) 0x758ad0
(gdb) print *((mfin::Account*)((void*)ptr.get()))
$12 = {<mcommon::Idable> = {_vptr.Idable = 0x4f0d78 <vtable for mfin::Account+56>,
id = "\363aL\000\000\000\000\000PbL\000\000\000\000\000\304\031L\000\000\000\000\000\021#L", '\000' <repeats 13 times>, " \232N", '\000' <repeats 21 times>, "P\251@\000\000\000\000\000\370\377\377\377\377\377\377\377 \232N", '\000' <repeats 21 times>, "\304\031L\000\000\000\000\000P\251@", '\000' <repeats 45 times>, "St19_Sp_counted_deleterIPN4mfin7AccountE"...}, <mfin::Position> = {<mgraph::Attribute> = {
_vptr.Attribute = 0x4f0570 <vtable for mfin::Currency+16>}, <mcommon::Displayable> = {_vptr.Displayable = 0x0}, <No data fields>}, balance = {<mcommon::Displayable> = {_vptr.Displayable = 0x0}, amount = 49,
code = (unknown: 7702648)}}
This is of course what happens in binding->second.shared_ptr (seen below) which takes a const void*.
(gdb) list
295 writeMetadata(ar);
296
297 #ifdef _MSC_VER
298 savePolymorphicSharedPtr( ar, dptr, ::cereal::traits::has_shared_from_this<T>::type() ); // MSVC doesn't like typename here
299 #else // not _MSC_VER
300 savePolymorphicSharedPtr( ar, dptr, typename ::cereal::traits::has_shared_from_this<T>::type() );
301 #endif // _MSC_VER
302 };
303
304 serializers.unique_ptr =
Now I believe this is expected as if I recall correctly there is something wrong about casting a polymorphic type to a void*. What is wrong in my usage of cereal that would cause this?
Aucun commentaire:
Enregistrer un commentaire