я использую зерновой, библиотека сериализации C ++ 11. Я не уверен, является ли это ошибкой в библиотеке или проблемой с ее использованием, и мне нужна помощь.
Учитывая следующее минимальное repro, которое является репрезентативным (но не зависимым) в моем собственном коде, я получаю исключение из JSONInputArchive :: search, которое вызывается строкой рядом с моим комментарием в примере кода ниже (// прерывается здесь.)
Я сейчас на коммите 436a0a275cda007f137876f37b4fc8783e615352 в этом github repro (на момент написания, кончик их развивать филиал.)
#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 (в cereal / 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».
У меня вопрос такой: я делаю что-то не так? Или есть проблема с хлопьями?
https://github.com/USCiLab/cereal/issues/42
Похоже, что это действительно ошибка с Cereal. Мой временный обходной путь выглядит следующим образом:
Сейчас, чтобы обойти проблему, я добавил строку 144 в memory.hpp (как
он появляется в строке 168 в случае отсутствия load_and_allocate, что означает
что есть конструктор по умолчанию.)ar (* ptr);
Я просто буду избегать использования архива load_and_allocate
напрямую и буду использовать мои функции сериализации. В моем
Метод load_and_allocate Я создам объект с информацией по умолчанию.
Когда это будет исправлено, я смогу правильно загрузить параметры, необходимые для правильного построения объекта.
* edit: это было исправлено в ветке разработки.
Других решений пока нет …