C++ 如何为Boost::Nested_容器实现Boost::Serialize
(后续行动) Serialize经常在oarchive上传递异常,抱怨重新创建特定对象会导致重复的对象。一些档案成功保存并重新加载,但许多档案会导致上述错误。我还无法确定发生错误的确切条件,但我已经证明,用于填充嵌套的_容器和平面对象列表的任何内容都不包含重复的对象ID。我使用的是文本存档,而不是二进制文件。下面是我如何修改嵌套的_容器以及另一个单独的平面对象列表的代码,以便执行Boost::Serialize:C++ 如何为Boost::Nested_容器实现Boost::Serialize,c++,serialization,boost,boost-multi-index,C++,Serialization,Boost,Boost Multi Index,(后续行动) Serialize经常在oarchive上传递异常,抱怨重新创建特定对象会导致重复的对象。一些档案成功保存并重新加载,但许多档案会导致上述错误。我还无法确定发生错误的确切条件,但我已经证明,用于填充嵌套的_容器和平面对象列表的任何内容都不包含重复的对象ID。我使用的是文本存档,而不是二进制文件。下面是我如何修改嵌套的_容器以及另一个单独的平面对象列表的代码,以便执行Boost::Serialize: struct obj { int id;
struct obj
{
int id;
const obj * parent = nullptr;
obj()
:id(-1)
{ }
obj(int object)
:id(object)
{ }
int getObjId() const
{
return id;
}
bool operator==(obj obj2)
{
if (this->getObjId() == obj2.getObjId())
return true;
else
return false;
}
#if 1
private:
friend class boost::serialization::access;
friend std::ostream & operator<<(std::ostream &os, const obj &obj);
template<class Archive>
void serialize(Archive &ar, const unsigned int file_version)
{
ar & id & parent;
}
#endif
};
struct subtree_obj
{
const obj & obj_;
subtree_obj(const obj & ob)
:obj_(ob)
{ }
#if 1
private:
friend class boost::serialization::access;
friend std::ostream & operator<<(std::ostream &os, const subtree_obj &obj);
template<class Archive>
void serialize(Archive &ar, const unsigned int file_version)
{
ar & obj_;
}
#endif
};
struct path
{
int id;
const path *next = nullptr;
path(int ID, const path *nex)
:id(ID), next(nex)
{ }
path(int ID)
:id(ID)
{ }
#if 1
private:
friend class boost::serialization::access;
friend std::ostream & operator<<(std::ostream &os, const path &pathe);
template<class Archive>
void serialize(Archive &ar, const unsigned int file_version)
{
ar & id & next;
}
#endif
};
struct subtree_path
{
const path & path_;
subtree_path(const path & path)
:path_(path)
{ }
#if 1
private:
friend class boost::serialization::access;
friend std::ostream & operator<<(std::ostream &os, const subtree_path &pathe);
template<class Archive>
void serialize(Archive &ar, const unsigned int file_version)
{
ar & path_;
}
#endif
};
//
// My flattened object list
//
struct HMIObj
{
int objId;
std::string objType;
HMIObj()
:objId(-1), objType("")
{ }
bool operator==(HMIObj obj2)
{
if (this->getObjId() == obj2.getObjId())
&& this->getObjType() == obj2.getObjType())
return true;
else
return false;
}
int getObjId() const
{
return objId;
}
std::string getObjType() const
{
return objType;
}
#if 1
private:
friend class boost::serialization::access;
friend std::ostream & operator<<(std::ostream &os, const HMIObj &obj);
template<class Archive>
void serialize(Archive &ar, const unsigned int file_version)
{
ar & objId & objType;
}
#endif
};
结构对象
{
int-id;
const obj*parent=nullptr;
obj()
:id(-1)
{ }
obj(整型对象)
:id(对象)
{ }
int getObjId()常量
{
返回id;
}
布尔运算符==(obj obj2)
{
如果(this->getObjId()==obj2.getObjId())
返回true;
其他的
返回false;
}
#如果1
私人:
好友类boost::serialization::access;
friend std::ostream&operator您遇到的问题很可能是由于在索引#0(散列)中遍历元素的特定顺序造成的。例如,如果我们这样填充容器:
nested_container c;
c.insert({54});
auto it=c.insert({0}).first;
insert_under(c,it,{1});
然后这些元素在索引#0中列为(1,54,0)。这里的关键问题是1是0的子元素:当以保存元素的相同顺序加载元素时,第一个元素是1,但这需要在加载之前加载0才能正确指向它。这就是Boost的功能。序列化非常巧妙地检测并抱怨。这种子元素先于父元素的情况取决于非常不可预测的情况可以在散列索引中对元素进行排序,这就是您有时会看到问题的原因
您有两个简单的解决方案:
模板
void序列化(归档和ar、嵌套的容器和c、未签名的int)
{
如果constexpr(存档::正在保存::值){
boost::serialization::stl::save_集合(ar,c.get());
}
否则{
boost::serialization::load_set_集合(ar,c.get());
}
}
解决方案#2的完整演示代码如下:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <iterator>
struct obj
{
int id;
const obj* parent=nullptr;
};
namespace boost{
namespace serialization{
template<class Archive>
void serialize(Archive& ar,obj& x,unsigned int)
{
ar&x.id&x.parent;
}
}} /* namespace boost::serialization */
struct subtree_obj
{
const obj& obj_;
};
struct path
{
int id;
const path* next=nullptr;
};
struct subtree_path
{
const path& path_;
};
inline bool operator<(const path& x,const path& y)
{
if(x.id<y.id)return true;
else if(y.id<x.id)return false;
else if(!x.next) return y.next;
else if(!y.next) return false;
else return *(x.next)<*(y.next);
}
inline bool operator<(const subtree_path& sx,const path& y)
{
const path& x=sx.path_;
if(x.id<y.id)return true;
else if(y.id<x.id)return false;
else if(!x.next) return false;
else if(!y.next) return false;
else return subtree_path{*(x.next)}<*(y.next);
}
inline bool operator<(const path& x,const subtree_path& sy)
{
return x<sy.path_;
}
struct obj_less
{
private:
template<typename F>
static auto apply_to_path(const obj& x,F f)
{
return apply_to_path(x.parent,path{x.id},f);
}
template<typename F>
static auto apply_to_path(const obj* px,const path& x,F f)
->decltype(f(x))
{
return !px?f(x):apply_to_path(px->parent,{px->id,&x},f);
}
public:
bool operator()(const obj& x,const obj& y)const
{
return apply_to_path(x,[&](const path& x){
return apply_to_path(y,[&](const path& y){
return x<y;
});
});
}
bool operator()(const subtree_obj& x,const obj& y)const
{
return apply_to_path(x.obj_,[&](const path& x){
return apply_to_path(y,[&](const path& y){
return subtree_path{x}<y;
});
});
}
bool operator()(const obj& x,const subtree_obj& y)const
{
return apply_to_path(x,[&](const path& x){
return apply_to_path(y.obj_,[&](const path& y){
return x<subtree_path{y};
});
});
}
};
using namespace boost::multi_index;
using nested_container=multi_index_container<
obj,
indexed_by<
hashed_unique<member<obj,int,&obj::id>>,
ordered_unique<identity<obj>,obj_less>
>
>;
#if 1 /* set to 0 to trigger pointer conflict exception */
#include <boost/serialization/set.hpp>
namespace boost{
namespace serialization{
template<class Archive>
void serialize(Archive& ar,nested_container& c,unsigned int)
{
if constexpr(Archive::is_saving::value){
boost::serialization::stl::save_collection(ar,c.get<1>());
}
else{
boost::serialization::load_set_collection(ar,c.get<1>());
}
}
}} /* namespace boost::serialization */
#endif
template<typename Iterator>
inline auto insert_under(nested_container& c,Iterator it,obj x)
{
x.parent=&*it;
return c.insert(std::move(x));
}
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <iostream>
#include <sstream>
void print(const nested_container& c)
{
for(const obj& x:c){
std::cout<<"("<<x.id;
if(x.parent)std::cout<<"->"<<x.parent->id;
std::cout<<")";
}
std::cout<<"\n";
}
int main()
{
nested_container c;
c.insert({54});
auto it=c.insert({0}).first;
insert_under(c,it,{1});
print(c);
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
oa<<c;
nested_container c2;
std::istringstream iss(oss.str());
boost::archive::text_iarchive ia(iss);
ia>>c2;
print(c2);
}
#包括
#包括
#包括
#包括
#包括
#包括
结构对象
{
int-id;
const obj*parent=nullptr;
};
名称空间提升{
命名空间序列化{
模板
无效序列化(存档和ar、obj和x、未签名整数)
{
ar&x.id&x.parent;
}
}}/*名称空间boost::序列化*/
结构子树
{
const obj和obj_;
};
结构路径
{
int-id;
const path*next=nullptr;
};
结构子树路径
{
const path和path_u2;;
};
内联布尔运算符为提醒起见,我将从serialize中删除子树对象、路径和子树路径,并验证这是否解决了oarchive投诉。请注意,是否为子树对象
、路径
和子树路径
序列化与原始问题无关。我实施了解决方案#1并运行了几个非常复杂的测试,所有这些测试以前都失败了——现在都通过了!我对您的知识和专业技能印象深刻。我将更仔细地检查解决方案#2,并很快实施它,以取代解决方案#1。我还对Boost::Multi index和Boost的专业水平印象深刻::Serialize已经实现了!我已经成为了一个超级粉丝。再一次,Joaquin,谢谢你。我将在这里深入研究你的代码以彻底掌握它。我可能有一些问题,但我不想简单地使用它而不理解它。
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <iterator>
struct obj
{
int id;
const obj* parent=nullptr;
};
namespace boost{
namespace serialization{
template<class Archive>
void serialize(Archive& ar,obj& x,unsigned int)
{
ar&x.id&x.parent;
}
}} /* namespace boost::serialization */
struct subtree_obj
{
const obj& obj_;
};
struct path
{
int id;
const path* next=nullptr;
};
struct subtree_path
{
const path& path_;
};
inline bool operator<(const path& x,const path& y)
{
if(x.id<y.id)return true;
else if(y.id<x.id)return false;
else if(!x.next) return y.next;
else if(!y.next) return false;
else return *(x.next)<*(y.next);
}
inline bool operator<(const subtree_path& sx,const path& y)
{
const path& x=sx.path_;
if(x.id<y.id)return true;
else if(y.id<x.id)return false;
else if(!x.next) return false;
else if(!y.next) return false;
else return subtree_path{*(x.next)}<*(y.next);
}
inline bool operator<(const path& x,const subtree_path& sy)
{
return x<sy.path_;
}
struct obj_less
{
private:
template<typename F>
static auto apply_to_path(const obj& x,F f)
{
return apply_to_path(x.parent,path{x.id},f);
}
template<typename F>
static auto apply_to_path(const obj* px,const path& x,F f)
->decltype(f(x))
{
return !px?f(x):apply_to_path(px->parent,{px->id,&x},f);
}
public:
bool operator()(const obj& x,const obj& y)const
{
return apply_to_path(x,[&](const path& x){
return apply_to_path(y,[&](const path& y){
return x<y;
});
});
}
bool operator()(const subtree_obj& x,const obj& y)const
{
return apply_to_path(x.obj_,[&](const path& x){
return apply_to_path(y,[&](const path& y){
return subtree_path{x}<y;
});
});
}
bool operator()(const obj& x,const subtree_obj& y)const
{
return apply_to_path(x,[&](const path& x){
return apply_to_path(y.obj_,[&](const path& y){
return x<subtree_path{y};
});
});
}
};
using namespace boost::multi_index;
using nested_container=multi_index_container<
obj,
indexed_by<
hashed_unique<member<obj,int,&obj::id>>,
ordered_unique<identity<obj>,obj_less>
>
>;
#if 1 /* set to 0 to trigger pointer conflict exception */
#include <boost/serialization/set.hpp>
namespace boost{
namespace serialization{
template<class Archive>
void serialize(Archive& ar,nested_container& c,unsigned int)
{
if constexpr(Archive::is_saving::value){
boost::serialization::stl::save_collection(ar,c.get<1>());
}
else{
boost::serialization::load_set_collection(ar,c.get<1>());
}
}
}} /* namespace boost::serialization */
#endif
template<typename Iterator>
inline auto insert_under(nested_container& c,Iterator it,obj x)
{
x.parent=&*it;
return c.insert(std::move(x));
}
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <iostream>
#include <sstream>
void print(const nested_container& c)
{
for(const obj& x:c){
std::cout<<"("<<x.id;
if(x.parent)std::cout<<"->"<<x.parent->id;
std::cout<<")";
}
std::cout<<"\n";
}
int main()
{
nested_container c;
c.insert({54});
auto it=c.insert({0}).first;
insert_under(c,it,{1});
print(c);
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
oa<<c;
nested_container c2;
std::istringstream iss(oss.str());
boost::archive::text_iarchive ia(iss);
ia>>c2;
print(c2);
}