用C++中的指针序列化类
Serializing a class with a pointer in C++
我想序列化Person
类型的对象。我想以后用它来保存数据,甚至保存游戏。我知道如何对像int
、char
、bool
这样的基元,甚至像char[]
这样的c字符串执行此操作。
问题是,我希望字符串尽可能大,而不是声明一个大小为256的char
数组,并希望没有人输入太大的内容。我读到序列化一个以std::string
为成员的类不起作用,因为它有一个内部指针,但有没有办法序列化我的以char*
为成员的类?
我知道Boost有一个序列化库,但我想在不需要外部库的情况下完成这项工作,这似乎是一个很好的尝试活动。
这是我的Person
类:
class Person
{
private:
char* _fname;
char* _lname;
public:
Person();
Person(const char* fname, const char* lname);
Person(const string& fname, const string& lname);
string fname() const;
void fname(const char* fname);
void fname(const string& fname);
string lname() const;
void lname(const char* lname);
void lname(const string& lname);
};
第一:在类中使用std::string,从长远来看,它会让你的生活变得更轻松。
但这个建议对std::string和char*都有效(需要一些明显的小调整)。
基本上,您希望序列化未知大小的数据(在编译时)。这意味着当您对数据进行去串行化时,您必须有一种技术来告诉数据的长度(在对象前面加一个大小),或者有一种方法来找到数据的结尾(终止标记)。
终止标记更易于序列化。但反序列化更难(因为您必须向前寻找结尾)。此外,您必须转义对象中出现的任何终止标记,并且反序列化必须知道转义并将其删除
因此,由于这种并发症,我宁愿不使用终止标记。因此,我在对象前面加了一个大小。这样做的代价是,我必须以一种不会破坏的方式对对象的大小进行编码。
因此,如果我们在一个对象前面加上它的大小,你可以这样做:
// Place a ':' between the string and the size.
// There must be a marker as >> will continue reading if
// fname contains a digit as its first character.
// I don;t like using a space as >> skips spaces if you are not carefull
// and it is hard to tell the start of the string if the first characters in fname
// are the space character.
std::cout << strlen(fname) << ":" << fname;
然后你可以像这样反序列化:
size_t size;
char mark;
std::cint >> size >> mark;
if (!std::cin || mark != ':')
{ throw BadDataException;
}
result = new char[size+1](); // Note the () to zero fill the array.
std::cin.read(result, size)
编辑1(基于注释)更新:与字符串一起使用:
size_t size;
char mark;
std::cint >> size >> mark;
if (!std::cin || mark != ':')
{ throw BadDataException;
}
std::string result(' ', size); // Initialize string with enough space.
std::cin.read(&result[0], size) // Just read directly into the string
编辑2(基于评论)
序列化字符串的Helper函数
struct StringSerializer
{
std::string& value;
StringSerializer(std::string const& v):value(const_cast<std::string&>(v)){}
friend std::ostream& operator<<(std::ostream& stream, StringSerializer const& data)
{
stream << data.value.size() << ':' << data.value;
}
friend std::istream& operator>>(std::istream& stream, StringSerializer const& data)
{
std::size_t size;
char mark(' ');
stream >> size >> mark;
if (!stream || mark != ':')
{ stream.setstate(std::ios::badbit);
return stream;
}
data.value.resize(size);
stream.read(&data.value[0], size);
}
};
序列化个人
std::ostream& operator<<(std::ostream& stream, Person const& data)
{
return stream << StringSerializer(data.fname) << " "
<< StringSerializer(data.lname) << " "
<< data.age << "n";
}
std::istream& operator>>(std::istream& stream, Person& data)
{
stream >> StringSerializer(data.fname)
>> StringSerializer(data.lname)
>> data.age;
std::string line;
std::getline(stream, line);
if (!line.empty())
{ stream.setstate(std::ios::badbit);
}
return stream;
}
用法:
int main()
{
Person p;
std::cin >> p;
std::cout << p;
std::ofstream f("data");
f << p;
}
不能序列化指针,需要序列化指向.的数据指针
您需要序列化整个对象网络,从Person
(或Game
)开始,并查看每个对象,从您的起始对象可以访问这些对象。
反序列化时,您从存储中读取数据,为该数据分配内存,并将此新分配的内存的地址用作Person
/Game
对象的成员
指针字段使它更难序列化,但也不是不可能序列化。如果您不想使用任何序列化库,下面是您可以做到的方法
您应该在序列化时确定所指向对象的大小(例如,它可能是固定大小的,也可能是末尾带有null字符的C字符串),然后您可以保存一个标记,指示您正在序列化一个间接对象以及所指向区域的大小和实际内容。
当您在反序列化过程中偶然发现该标记时,可以分配适当数量的内存,将对象复制到其中,并将指针存储到反序列化对象中的区域。
我建议使用向量来封装序列化。
#include <vector>
using namespace std;
map vector<unsigned char> cbuff;
inline cbuff vchFromString(const std::string &str) {
unsigned char *strbeg = (unsigned char*) str.c_str();
return cbuff(strbeg, strbeg + str.size());
}
inline std::string stringFromVch(const cbuff &vch) {
std::string res;
std::vector<unsigned char>::const_iterator vi = vch.begin();
while (vi != vch.end()) {
res += (char) (*vi);
vi++;
}
return res;
}
class Example
{
cbuff label;
Example(string labelIn)
{
SetLabel(labelIn);
}
IMPLEMENT_SERIALIZE
(
READWRITE(label);
)
void SetLabel(string labelIn)
{
label = vchFromString(labelIn);
}
string GetLabel()
{
return (stringFromVch(label));
}
};
- 使用指向 struc 的指针序列化结构
- 序列化和反序列化boost共享指针
- C++通过基类指针提升子类的序列化
- 如何使用带有非默认构造函数的指针来提升序列化
- C++ 从 Boost object_pool构造的指针的 Boost 二进制序列化
- 使用 boost::序列化将派生类指针序列化为向量时出现问题
- SFINAE 序列化共享指针失败
- 如何提升::序列化指针和参考
- c++ 序列化包含字符串和指向另一个对象的指针的对象
- 使用指针增强序列化
- 指针的提升序列化保存指针的十六进制值,而不是对象的内容
- Boost:当缺少类型时,如何通过基指针序列化/反序列化泛型类型集合
- 在没有包装器的情况下提高指向基元的指针的序列化
- 无法使C++提升指针序列化正常工作
- Qt-序列化一个树结构(大量指针)
- 提升序列化,类包括指针
- 指针的向量.提升序列化
- 提升:包含指针的类实例的序列化
- 如何序列化包含指向基元的指针的类
- 序列化指针本身而不是目标对象