我有一个树状结构需要序列化。典型结构,每个节点具有parent
成员和children
向量。 parent
是指向类的原始指针,children
是shared_ptr
vector
。现在看来序列化工作正常,但反序列化使parent
成员未初始化(指向0xcccccccc
或0x00000000
的指针(。
当实际的父对象尚未完成反序列化时,将加载parent
成员,即子对象的parent
成员是通过父对象的反序列化请求加载的children
。由于这是循环的,我想知道我是否需要采取特殊措施才能使其工作。
感谢您的帮助。
更新:这是我的序列化函数的样子:
template <typename Archive>
void serialize(Archive& archive, GameCore::GameObject& t, const unsigned int version)
{
archive & boost::serialization::base_object<GameCore::Object>(t);
archive & boost::serialization::base_object<GameCore::Updatable>(t);
archive & t.parent;
archive & t.transform;
archive & t.components;
archive & t.children;
}
如果我注释掉archive & t.children
,parent
会正确填充。
更新2:好的,我已经设法将其转换为显示问题的最小示例。应编译以下内容:
#include <boostarchivebinary_oarchive.hpp>
#include <boostarchivebinary_iarchive.hpp>
#include <fstream>
#include <memory>
#include <vector>
class A
{
public:
A() {}
A(const A& rhs) = delete;
int someInt = 0;
A* parent = nullptr;
std::vector<A*> children;
template <class Archive>
void serialize(Archive& archive, const unsigned int version)
{
archive & someInt;
archive & parent;
int count = children.size();
archive & count;
children.resize(count);
for (int i = 0; i < count; ++i)
{
A* ptr = children[i];
archive & ptr;
children[i] = ptr;
}
}
};
int main()
{
A* newA = new A();
newA->someInt = 0;
A* newPtr = new A();
newPtr->someInt = 5;
newPtr->parent = newA;
newA->children.push_back(newPtr);
// Save.
std::ofstream outputFile("test", std::fstream::out | std::fstream::binary);
if (outputFile.is_open())
{
boost::archive::binary_oarchive outputArchive(outputFile);
// Serialize objects.
outputArchive << newA;
outputFile.close();
}
delete newA;
delete newPtr;
A* loadedPtr = nullptr;
// Load.
std::ifstream inputFile("test", std::fstream::binary | std::fstream::in);
if (inputFile && inputFile.good() && inputFile.is_open())
{
boost::archive::binary_iarchive inputArchive(inputFile);
// Load objects.
inputArchive >> loadedPtr;
inputFile.close();
}
return 0;
}
单步执行代码。孩子的parent
始终保持为空。
好吧,显然我成了另一个倒霉虫的牺牲品。根据最新的Boost发布页面,Boost 1.55还没有针对VS2013的工作序列化库。谈论浪费的时间...
VisualStudio 2013/Visual C++ 12 的已知错误
Visual Studio 2013 在发布过程中发布得很晚,所以存在几个 未解决的问题。其中包括:
由于缺少包含,序列化无法编译。
我过去也有同样的问题,我没有从开箱即用中找到可靠的解决方案......但是下面的小技巧工作正常 - 您可以分别指定序列化和反序列化函数(不使用默认模板和 &-运算符(:
//! Serialization
void A::serialize(xml_oarchive& ar, const unsigned int version)
{
ar << value;
}
//! De-serialization
void A::serialize(xml_iarchive& ar, const unsigned int version)
{
ar >> value;
}
之后,您可以在反序列化方法中指定还原指向父对象的指针,如下所示:
//! Serialization
void A::serialize(xml_oarchive& ar, const unsigned int version)
{
ar << children;
}
//! De-serialization
void A::serialize(xml_iarchive& ar, const unsigned int version)
{
ar >> children;
for(var child: children)
child->parent = this;
}
此问题已在开发分支上解决。
请参阅 https://svn.boost.org/trac/boost/ticket/9601
如果您使用Boost Serialization,则所有内容都应该开箱即用。您的类序列化可能看起来像
#include <boost/serialization/vector.hpp>
void serialize (Archive&ar, unsigned int version)
{
//declare possible derived types of nodes
ar & parent;
ar & children;
}
存档将散列指针,因此它不会多次创建每个元素。
一个重要的细节:如果你的节点可以是某种派生类型,你需要教存档在//地方期望什么类型,请参阅有关通过指向基类型的指针序列化派生类型的 Boost 文档中的详细信息。
如果您确定您的树结构是正确的且自包含的(root 具有 NULL 作为父节点,所有其他节点都是其各自"父节点"的"子节点"等(,那么您可以更有效地组织代码:
#include <boost/serialization/vector.hpp>
void serialize (Archive&ar, unsigned int version)
{
//declare possible derived types of nodes (either here or at archive creation point)
ar & children;
if (typename Archive::is_loading())
{
for (auto child : children)
child->parent = this;
}
}
(我假设您在构造函数中将"父"设置为 NULL(。
我没有用VS 2013测试这段代码。