0

我正在使用谷物,一个 C++11 序列化库。我不确定这是库的错误还是我如何使用它的问题,我需要一些帮助。

鉴于以下对我自己的代码具有代表性(但不依赖于)的最小重现,我收到 JSONInputArchive::search 引发的异常,正如下面代码示例中我的评论旁边的行所调用的那样(//breaks here。)

我目前在这个 github repro 中提交436a0a275cda007f137876f37b4fc8783e615352(在撰写本文时,他们的开发分支的提示。)

#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();
}

我从上面得到的示例输出(在异常之前)是:

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

我已经修改了 throwing 方法(在 grain/archive/json.hpp 中)以打印它正在搜索的内容以及它正在查看的每个值以调试问题。这是我的修改版本:

  //! 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");
  }

上述方法的输出之前除外:

!derivedMember == id
!derivedMember == data

我从中得到的输出似乎表明搜索正在查看“test.ptr_wrapper”的成员而不是“test.ptr_wrapper.data”。

我的问题是:我做错了什么吗?还是麦片有问题?

4

1 回答 1

0

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

看起来这确实是谷物的一个错误。我的临时解决方法如下:

现在,为了解决这个问题,我在 memory.hpp 中添加了第 144 行(因为它在没有 load_and_allocate 的情况下出现在第 168 行,这意味着有一个默认构造函数。)

ar(*ptr);

我将简单地避免直接使用 load_and_allocate 存档,并将使用我的序列化函数。在我的 load_and_allocate 方法中,我将构造一个带有“默认”信息的对象。

修复此问题后,我应该能够正确加载正确构造对象所需的参数。

*编辑:这已在开发分支上修复。

于 2014-01-06T06:20:07.270 回答