[英]Serialize C++ object without knowing its fields
我正在尝试学习如何序列化 C++ 对象。 在这里阅读了几篇文章后,使用boost
序列化函数和使用加载/保存函数进行归档似乎是一个好主意。 但是,我想避免使用 boost 库。
从概念上讲,我可以在不知道其字段的情况下保存对象吗? 在 C++ 中没有反射,存储对象的唯一方法是知道它的所有类成员。
可以使用stringstream
和重载<<
操作符将一个对象转成字符串,可以直接保存一个对象吗?
谢谢,K。
从概念上讲,我可以在不知道其字段的情况下保存对象吗?
不,你不能。
在 C++ 中没有反射,存储对象的唯一方法是知道它的所有类成员。
是的。 最好的方法是将知识封装在该类本身中:
class MyClass {
public:
std::ostream& put(std::ostream& os) const {
os << field1 << " " << field2 << std::endl;
return os;
}
friend std::ostream& operator<<(std::ostream& os, const MyClass& myclass) {
return myClass.put(os);
}
private:
int field1;
double field2;
};
您可以采用的一种方法是默认支持 tuple-likes 和 iterables。
有一个 read_archive 和 write_archive ,它首先执行花哨的 sfinae 来检测支持for(:)
循环的类型,以及支持std::tuple_size
和 ADL get<I>
的类似元组的类型。
这也符合 C++17 中一种形式的结构化绑定支持。
接下来,有一个基于to_tie
adl 的实现,它检查to_tie()
和to_tie(.)
。 如果是这样并且可以读/写,请使用它。
也许那里的某个地方包括一个archive_io
函数的adl查找,所以你可以明确地编写你自己的io。
目标是尽可能多地自动存档,以及您无法轻松编写的内容。
如果您想像真正的快照一样复制对象,我们可以逐个读取对象中的字节并将它们存储为字符并将它们粘贴到另一个对象或将其保存在文件中。 这是一个粗略的想法:
#include <iostream>
#include <iomanip>
struct Serialization
{
std::string data;
template <class T>
void in(const T &obj)
{
auto size = sizeof(T);
const char *ptr = (const char *)&obj;
for (size_t i = 0; i < size; i++)
data.push_back(*(ptr + i));
}
template <class T>
void out(T &obj)
{
char *ptr = (char *)&obj;
for (size_t i = 0; i < data.size(); i++)
*(ptr + i) = data[i];
}
void clear() { data.clear(); }
};
我们不知道对象内部是什么,它只是按原样复制。 这在某种程度上很容易使用,因为浅拷贝任何对象,但在
有一些指针家族成员(原始指针、智能指针、std::vector、...)拥有对象之外的一些内存。 只复制指针,但不会复制目标存储器。
它还复制了一个类的 vtable 指针,我不知道它是否有用。
例子:
class person
{
int age;
char name[3];
float height;
public:
person() = default;
person(int a, char n[3], float h) : age{a}, height{h}
{
for (size_t i = 0; i < 3; i++)
name[i] = n[i];
}
void print()
{
std::cout << age << " " << name[0] << name[1] << name[2] << " " << height << "\n";
}
};
int main()
{
char x[3] = {'1', '2', '3'};
person m{12, x, 180};
person n;
Serialization s;
s.in(m);
s.out(n);
n.print(); // 12 123 180
s.clear();
double d;
s.in(1.2345678910);
s.out(d);
std::cout << std::setprecision(10) << d; // 1.234567891
return 0;
}
序列化类可以扩展为序列化多个相同/不同的对象,方法是对写入字符串进行一些转换,比如重复
object name size => object name => object data size => object data
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.