Pregunta

I am using cereal, a C++11 serialization library. I am uncertain if this is a bug with the library or an issue with how I am using it and I would like some assistance.

Given the following minimal repro which is representative (but not reliant) on my own code I am getting an exception thrown from JSONInputArchive::search as invocated by the line next to my comment in the code sample below (//breaks here.)

I'm currently on commit 436a0a275cda007f137876f37b4fc8783e615352 in this github repro (at the time of writing, the tip of their develop branch.)

#include <iostream>
#include <sstream>
#include <string>
#include <map>

#include "cereal/cereal.hpp"
#include "cereal/types/map.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/types/memory.hpp"
#include "cereal/types/string.hpp"
#include "cereal/types/base_class.hpp"

#include "cereal/archives/json.hpp"
#include <cereal/types/polymorphic.hpp>

class BaseClass : public std::enable_shared_from_this<BaseClass> {
public:
    virtual ~BaseClass(){}

    template <class Archive>
    void serialize(Archive & archive){
        archive(CEREAL_NVP(name), CEREAL_NVP(baseMember));
    }
protected:
    BaseClass(const std::string &a_name):
        name(a_name){
    }

    std::string name;
    int baseMember; //let this have random junk so we can see if it saves right.
};

class DerivedClass : public BaseClass {
    friend cereal::access;
public:
    static std::shared_ptr<DerivedClass> make(const std::string &a_name, int a_derivedMember){
        return std::shared_ptr<DerivedClass>(new DerivedClass(a_name, a_derivedMember));
    }

    template <class Archive>
    void serialize(Archive & archive){
        archive(CEREAL_NVP(derivedMember), cereal::make_nvp("base", cereal::base_class<BaseClass>(this)));
    }
private:
    DerivedClass(const std::string &a_name, int a_derivedMember):
        BaseClass(a_name),
        derivedMember(a_derivedMember){
    }

    template <class Archive>
    static DerivedClass * load_and_allocate(Archive &archive){
        int derivedMember;
        archive(CEREAL_NVP(derivedMember)); //breaks here.
        DerivedClass* object = new DerivedClass("", derivedMember);
        archive(cereal::make_nvp("base", cereal::base_class<BaseClass>(object)));
        return object;
    }

    int derivedMember;
};

CEREAL_REGISTER_TYPE(DerivedClass);

void saveTest(){
    std::stringstream stream;
    {
        cereal::JSONOutputArchive archive(stream);
        auto testSave = DerivedClass::make("TestName", 4);
        archive(cereal::make_nvp("test", testSave));
    }
    std::cout << stream.str() << std::endl;
    std::shared_ptr<DerivedClass> loaded;
    {
        cereal::JSONInputArchive archive(stream);
        archive(cereal::make_nvp("test", loaded));
    }
    std::stringstream stream2;
    {
        cereal::JSONOutputArchive archive(stream2);
        archive(cereal::make_nvp("test", loaded));
    }
    std::cout << stream2.str() << std::endl;
    std::cout << "TA-DA!" << std::endl;
}

int main(){
    saveTest();
}

The sample output I get from the above (before the exception) is:

{
    "test": {
        "id": 1073741824,
        "ptr_wrapper": {
            "id": 2147483649,
            "data": {
                "derivedMember": 4,
                "base": {
                    "name": "TestName",
                    "baseMember": -1163005939
                }
            }
        }
    }
}

I've modified the throwing method (in cereal/archive/json.hpp) to print what it is searching for and each of the values it is looking through in an effort to debug the problem. Here is my modified version:

  //! Adjust our position such that we are at the node with the given name
  /*! @throws Exception if no such named node exists */
  inline void search( const char * searchName )//, GenericValue const & parent )
  {
    size_t index = 0;
    std::cout << "_____" << std::endl;
    for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
      if( std::strcmp( searchName, it->name.GetString() ) == 0 )
      {
        itsIndex = index;
        return;
      } else{
          //I added this part here
          std::cout << "!" << searchName << " == " << it->name.GetString() << std::endl;
      }

    throw Exception("JSON Parsing failed - provided NVP not found");
  }

Output for the above method before it excepts:

!derivedMember == id
!derivedMember == data

The output I get from this seems to indicate that search is looking through the members of "test.ptr_wrapper" instead of "test.ptr_wrapper.data".

My question is this: am I doing something wrong? Or is there an issue with cereal?

¿Fue útil?

Solución

https://github.com/USCiLab/cereal/issues/42

It seems like this is indeed a bug with Cereal. My temporary work-around is as follows:

For now, to work around the issue I added a line 144 in memory.hpp (as it appears on line 168 in the case of no load_and_allocate which means that there is a default constructor.)

ar( *ptr );

I will simply avoid using the load_and_allocate archive directly and will use my serialization functions. In my load_and_allocate method I will construct an object with "default" like information.

When this is fixed I should be able to correctly load in the parameters required to construct the object properly.

*edit: this has been fixed on the develop branch.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top