促进二进制反序列化
Boost Binary Deserialization
我创建一个 D&D 引擎只是为了好玩,只是为了练习我的 C++ 技能并学习一些更深入的主题。目前,我正在构建一个系统来保存和加载角色。我有一个 Stats class,它保存了一个角色的所有统计数据,还有一个角色 class,目前只有一个名字和一个 stats* 到该角色的统计对象。
到目前为止,我已经能够使用 boost 文本存档成功保存数据,现在切换到 boost 二进制存档。保存数据时它似乎可以工作,但是当我尝试加载数据时出现此错误:
“未处理的异常 - VileEngine.exe Microsoft C++ 异常中 [内存地址] 处的未处理异常:boost::archive::archive_exception 在内存位置 [不同的内存地址]”
我可以多次跳过这个错误,但是当程序运行和加载时,加载角色的数据有很大偏差,所以我知道它必须是我保存它的方式,或者更有可能以我加载它的方式。我试过通读 boost 文档,但找不到修复它的方法。我也尝试搜索其他 posts 但找不到答案,或者我只是不明白答案。非常感谢任何帮助。
相关代码post编在下面。如果需要,我可以 post 所有代码,但对于所有 classes 来说,它已经相当多了。
在Character.hpp
private:
friend class boost::serialization::access; //allows serialization saving
//creates the template class used by boost to serialize the classes data
//serialize is call whenever this class is attempting to be saved
template<class Archive>
void serialize(Archive& ar, const unsigned int version) {
ar << name;
ar << *charStats;
ar << inventory;
}
/*********************************
* Data Members
***********************************/
std::string name;
Stats* charStats;
std::vector<std::string> inventory;
public:
Character();
void loadCharacter(std::string &charName); //saves all character details
void saveCharacter(); //loads all character details
在Character.cpp
/*********************************************
Functions to save and load character details
**********************************************/
void Character::saveCharacter() {
//save all details of character to charactername.dat file
//create filename of format "CharacterName.dat"
std::string fileName = name + ".dat";
std::ofstream saveFile(fileName);
//create serialized archive and save this characters data
boost::archive::binary_oarchive outputArchive(saveFile);
outputArchive << this;
saveFile.close();
}
void Character::loadCharacter(std::string &charName) {
//load details of .dat file into character using the characters name
std::string fileName = charName + ".dat";
std::ifstream loadFile(fileName);
boost::archive::binary_iarchive inputArchive(loadFile);
inputArchive >> name;
Stats* temp = new Stats;
inputArchive >> temp;
charStats = temp;
inputArchive >> inventory;
loadFile.close();
}
在Stats.hpp
private:
friend class boost::serialization::access; //allows serialization saving
//creates the template class used by boost to serialize the classes data
//serialize is call whenever this class is attempting to be saved
template<class Archive>
void serialize(Archive& ar, const unsigned int version) {
ar & skillSet;
ar & subSkillMap;
ar & level;
ar & proficiencyBonus;
}
当你保存时,你只写this
(通过指针,这是一个错误,见下文):
boost::archive::binary_oarchive outputArchive(saveFile);
outputArchive << this;
加载时,您会以某种方式阅读三个不同的内容。为什么?他们显然应该匹配。和 100%。所以:
void Character::saveCharacter() {
std::ofstream saveFile(name + ".dat");
boost::archive::binary_oarchive outputArchive(saveFile);
outputArchive << *this;
}
您保存 *this
(通过引用)是因为您不希望反序列化在堆上分配新的 Character 实例。如果这样做,则不能使其成为成员函数。
无论如何,您的序列化函数在必须使用 operator&
的地方使用 operator<<
,否则它只能用于保存,不能用于加载。您的编译器会很清楚地告诉您,您的代码与您发布的代码不同。
现场观看:Live On Coliru
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <fstream>
struct Stats{
private:
std::set<int> skillSet{1, 2, 3};
std::map<int, std::string> subSkillMap{
{1, "one"},
{2, "two"},
{3, "three"},
};
int level = 13;
double proficiencyBonus = 0;
friend class boost::serialization::access; //allows serialization saving
template <class Archive> void serialize(Archive& ar, unsigned)
{
ar & skillSet;
ar & subSkillMap;
ar & level;
ar & proficiencyBonus;
}
};
struct Character {
private:
friend class boost::serialization::access; // allows serialization saving
template <class Archive>
void serialize(Archive& ar, const unsigned int version)
{
ar & name;
ar & *charStats;
ar & inventory;
}
/*********************************
* Data Members
*********************************/
std::string name;
Stats* charStats = new Stats{};
std::vector<std::string> inventory;
public:
Character(std::string name = "unnamed") : name(std::move(name)){}
~Character() { delete charStats; }
// rule of three (suggest to use no raw pointers!)
Character(Character const&) = delete;
Character& operator=(Character const&) = delete;
void loadCharacter(std::string const& charName);
void saveCharacter();
};
/*********************************************
Functions to save and load character details
**********************************************/
void Character::saveCharacter() {
std::ofstream saveFile(name + ".dat");
boost::archive::binary_oarchive outputArchive(saveFile);
outputArchive << *this;
}
void Character::loadCharacter(std::string const &charName) {
std::ifstream loadFile(charName + ".dat");
boost::archive::binary_iarchive inputArchive(loadFile);
inputArchive >> *this;
loadFile.close();
}
int main() {
{
Character charlie { "Charlie" }, bokimov { "Bokimov" };
charlie.saveCharacter();
bokimov.saveCharacter();
}
{
Character someone, someone_else;
someone.loadCharacter("Charlie");
someone_else.loadCharacter("Bokimov");
}
}
保存两个文件并加载它们:
==== Bokimov.dat ====
00000000: 1600 0000 0000 0000 7365 7269 616c 697a ........serializ
00000010: 6174 696f 6e3a 3a61 7263 6869 7665 1300 ation::archive..
00000020: 0408 0408 0100 0000 0000 0000 0007 0000 ................
00000030: 0000 0000 0042 6f6b 696d 6f76 0000 0000 .....Bokimov....
00000040: 0003 0000 0000 0000 0000 0000 0001 0000 ................
00000050: 0002 0000 0003 0000 0000 0000 0000 0300 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0001 ................
00000070: 0000 0003 0000 0000 0000 006f 6e65 0200 ...........one..
00000080: 0000 0300 0000 0000 0000 7477 6f03 0000 ..........two...
00000090: 0005 0000 0000 0000 0074 6872 6565 0d00 .........three..
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 00 ...........
==== Charlie.dat ====
00000000: 1600 0000 0000 0000 7365 7269 616c 697a ........serializ
00000010: 6174 696f 6e3a 3a61 7263 6869 7665 1300 ation::archive..
00000020: 0408 0408 0100 0000 0000 0000 0007 0000 ................
00000030: 0000 0000 0043 6861 726c 6965 0000 0000 .....Charlie....
00000040: 0003 0000 0000 0000 0000 0000 0001 0000 ................
00000050: 0002 0000 0003 0000 0000 0000 0000 0300 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0001 ................
00000070: 0000 0003 0000 0000 0000 006f 6e65 0200 ...........one..
00000080: 0000 0300 0000 0000 0000 7477 6f03 0000 ..........two...
00000090: 0005 0000 0000 0000 0074 6872 6565 0d00 .........three..
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 00 ...........
我创建一个 D&D 引擎只是为了好玩,只是为了练习我的 C++ 技能并学习一些更深入的主题。目前,我正在构建一个系统来保存和加载角色。我有一个 Stats class,它保存了一个角色的所有统计数据,还有一个角色 class,目前只有一个名字和一个 stats* 到该角色的统计对象。
到目前为止,我已经能够使用 boost 文本存档成功保存数据,现在切换到 boost 二进制存档。保存数据时它似乎可以工作,但是当我尝试加载数据时出现此错误:
“未处理的异常 - VileEngine.exe Microsoft C++ 异常中 [内存地址] 处的未处理异常:boost::archive::archive_exception 在内存位置 [不同的内存地址]”
我可以多次跳过这个错误,但是当程序运行和加载时,加载角色的数据有很大偏差,所以我知道它必须是我保存它的方式,或者更有可能以我加载它的方式。我试过通读 boost 文档,但找不到修复它的方法。我也尝试搜索其他 posts 但找不到答案,或者我只是不明白答案。非常感谢任何帮助。
相关代码post编在下面。如果需要,我可以 post 所有代码,但对于所有 classes 来说,它已经相当多了。
在Character.hpp
private:
friend class boost::serialization::access; //allows serialization saving
//creates the template class used by boost to serialize the classes data
//serialize is call whenever this class is attempting to be saved
template<class Archive>
void serialize(Archive& ar, const unsigned int version) {
ar << name;
ar << *charStats;
ar << inventory;
}
/*********************************
* Data Members
***********************************/
std::string name;
Stats* charStats;
std::vector<std::string> inventory;
public:
Character();
void loadCharacter(std::string &charName); //saves all character details
void saveCharacter(); //loads all character details
在Character.cpp
/*********************************************
Functions to save and load character details
**********************************************/
void Character::saveCharacter() {
//save all details of character to charactername.dat file
//create filename of format "CharacterName.dat"
std::string fileName = name + ".dat";
std::ofstream saveFile(fileName);
//create serialized archive and save this characters data
boost::archive::binary_oarchive outputArchive(saveFile);
outputArchive << this;
saveFile.close();
}
void Character::loadCharacter(std::string &charName) {
//load details of .dat file into character using the characters name
std::string fileName = charName + ".dat";
std::ifstream loadFile(fileName);
boost::archive::binary_iarchive inputArchive(loadFile);
inputArchive >> name;
Stats* temp = new Stats;
inputArchive >> temp;
charStats = temp;
inputArchive >> inventory;
loadFile.close();
}
在Stats.hpp
private:
friend class boost::serialization::access; //allows serialization saving
//creates the template class used by boost to serialize the classes data
//serialize is call whenever this class is attempting to be saved
template<class Archive>
void serialize(Archive& ar, const unsigned int version) {
ar & skillSet;
ar & subSkillMap;
ar & level;
ar & proficiencyBonus;
}
当你保存时,你只写this
(通过指针,这是一个错误,见下文):
boost::archive::binary_oarchive outputArchive(saveFile);
outputArchive << this;
加载时,您会以某种方式阅读三个不同的内容。为什么?他们显然应该匹配。和 100%。所以:
void Character::saveCharacter() {
std::ofstream saveFile(name + ".dat");
boost::archive::binary_oarchive outputArchive(saveFile);
outputArchive << *this;
}
您保存 *this
(通过引用)是因为您不希望反序列化在堆上分配新的 Character 实例。如果这样做,则不能使其成为成员函数。
无论如何,您的序列化函数在必须使用 operator&
的地方使用 operator<<
,否则它只能用于保存,不能用于加载。您的编译器会很清楚地告诉您,您的代码与您发布的代码不同。
现场观看:Live On Coliru
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <fstream>
struct Stats{
private:
std::set<int> skillSet{1, 2, 3};
std::map<int, std::string> subSkillMap{
{1, "one"},
{2, "two"},
{3, "three"},
};
int level = 13;
double proficiencyBonus = 0;
friend class boost::serialization::access; //allows serialization saving
template <class Archive> void serialize(Archive& ar, unsigned)
{
ar & skillSet;
ar & subSkillMap;
ar & level;
ar & proficiencyBonus;
}
};
struct Character {
private:
friend class boost::serialization::access; // allows serialization saving
template <class Archive>
void serialize(Archive& ar, const unsigned int version)
{
ar & name;
ar & *charStats;
ar & inventory;
}
/*********************************
* Data Members
*********************************/
std::string name;
Stats* charStats = new Stats{};
std::vector<std::string> inventory;
public:
Character(std::string name = "unnamed") : name(std::move(name)){}
~Character() { delete charStats; }
// rule of three (suggest to use no raw pointers!)
Character(Character const&) = delete;
Character& operator=(Character const&) = delete;
void loadCharacter(std::string const& charName);
void saveCharacter();
};
/*********************************************
Functions to save and load character details
**********************************************/
void Character::saveCharacter() {
std::ofstream saveFile(name + ".dat");
boost::archive::binary_oarchive outputArchive(saveFile);
outputArchive << *this;
}
void Character::loadCharacter(std::string const &charName) {
std::ifstream loadFile(charName + ".dat");
boost::archive::binary_iarchive inputArchive(loadFile);
inputArchive >> *this;
loadFile.close();
}
int main() {
{
Character charlie { "Charlie" }, bokimov { "Bokimov" };
charlie.saveCharacter();
bokimov.saveCharacter();
}
{
Character someone, someone_else;
someone.loadCharacter("Charlie");
someone_else.loadCharacter("Bokimov");
}
}
保存两个文件并加载它们:
==== Bokimov.dat ====
00000000: 1600 0000 0000 0000 7365 7269 616c 697a ........serializ
00000010: 6174 696f 6e3a 3a61 7263 6869 7665 1300 ation::archive..
00000020: 0408 0408 0100 0000 0000 0000 0007 0000 ................
00000030: 0000 0000 0042 6f6b 696d 6f76 0000 0000 .....Bokimov....
00000040: 0003 0000 0000 0000 0000 0000 0001 0000 ................
00000050: 0002 0000 0003 0000 0000 0000 0000 0300 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0001 ................
00000070: 0000 0003 0000 0000 0000 006f 6e65 0200 ...........one..
00000080: 0000 0300 0000 0000 0000 7477 6f03 0000 ..........two...
00000090: 0005 0000 0000 0000 0074 6872 6565 0d00 .........three..
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 00 ...........
==== Charlie.dat ====
00000000: 1600 0000 0000 0000 7365 7269 616c 697a ........serializ
00000010: 6174 696f 6e3a 3a61 7263 6869 7665 1300 ation::archive..
00000020: 0408 0408 0100 0000 0000 0000 0007 0000 ................
00000030: 0000 0000 0043 6861 726c 6965 0000 0000 .....Charlie....
00000040: 0003 0000 0000 0000 0000 0000 0001 0000 ................
00000050: 0002 0000 0003 0000 0000 0000 0000 0300 ................
00000060: 0000 0000 0000 0000 0000 0000 0000 0001 ................
00000070: 0000 0003 0000 0000 0000 006f 6e65 0200 ...........one..
00000080: 0000 0300 0000 0000 0000 7477 6f03 0000 ..........two...
00000090: 0005 0000 0000 0000 0074 6872 6565 0d00 .........three..
000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000000b0: 0000 0000 0000 0000 0000 00 ...........