我正在使用C++中的sstream序列化std::map。序列化函数:
template <class key, class value>
std::string serializeMap(const std::map<key, value>& v){
std::stringstream ss;
std::for_each(v.begin(), v.end(), [&ss](const std::pair<key, value>& s){
ss.write ((char*)&s, sizeof(std::pair<key,value>));
});
return ss.str();
}并使用以下代码进行反序列化:
template <class key, class value>
void deSerializeMap(const std::string& s, std::map<key, value>& v){
std::stringstream ss1;
ss1<<s;
int pos = 0;
printf("\nlen %d\n", s.size());
while(ss1){
char* ar = new char[sizeof(std::pair<key, value>)];
ss1.read(ar, sizeof(std::pair<key, value>));
v.insert(*(reinterpret_cast<std::pair<key, value>*>(ar)));
pos+=sizeof(std::pair<key, value>);
ss1.seekg(pos);
delete[] ar;
}
}使用std::string时,这是预期的工作方式。我必须使用一个以const char*为参数的C函数,我尝试使用c_str()并将一个空字符添加到char数组中,但strlen给出的值为零。我是不是漏掉了什么?
发布于 2018-01-07 07:58:19
正如@Nir Friedman提到的,如果你正在实现一个序列化程序,而没有在容器的元素上调用它,那么你可能做错了什么。
进行这种递归序列化意味着将POD类型作为"atoms“(递归结束条件),递归步骤是在非POD类型的每个成员上调用序列化程序。
要实现您想要的功能,一个简单的方法是使用如下所示的函数模板:
template <typename T>
uint64_t write(const T& t);write函数通常返回序列化的字节数的无符号整数。这个模板化函数应该专门用于所有POD和您希望序列化的任何非POD类型。所以在你的例子中,除了int,float,double,char等等。您需要对映射进行遍历并对每个键值对调用write的write(const std::map<K,T>& m)。此外,对于序列化,通常在实际数据之前编写一个头,以便可以反序列化数据(例如,如何知道映射包含多少元素?)。
幸运的是(也许)对您来说,标准库有这样一个模式(请参阅“装饰器”模式),正如@ Alexander Huszagh所提到的,那就是流运算符(operator<<),它可以在任何POD类型上调用,所以序列化std::map的(简单而简单的)方法是:
template<typename K, typename V>
std::ostream& operator<<(std::ostream& os, const std::map<K,V>& m)
{
os << "map" << '\n'; //write the type
os << m.size() << '\n'; //write the size of the data
for(auto&& kvp : m)
{
os << "pair" << '\n';
os << kvp.first << '\n'; //Recursive call here...
os << kvp.second << '\n'; //Recursive call here...
}
return os;
}上面的代码将很难反序列化,因为递归调用可能只需要一个数字、字符或字符串(带新行),而不会添加我添加的"header“,但是您的代码似乎假设它知道Key和Value模板参数,所以它可能对您没问题。
无论如何,你不应该尝试自己编写序列化程序,这是一项艰巨的工作,使其正确和通用,也是完全浪费时间,因为在web上有很多公开可用的。既然您对序列化映射感兴趣,我建议您使用一些JSON库。
https://stackoverflow.com/questions/48084507
复制相似问题