[英]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.