c++ - 使用 Fstream 序列化无序映射
问题描述
我需要序列化一个无序的地图。下面的方法用于fstream
以二进制模式读取和写入数据到映射中。但是,它会在清除地图并将其重新加载后打印0
而不是打印。这些功能在修改为与 a而不是一起使用时可以正常工作。5
vector
unordered_map
#include <iostream>
#include <unordered_map>
#include <fstream>
using namespace std;
void saveData(unordered_map<int, int>* p_map_ptr) {
fstream file("data.bin", ios::out | ios::binary);
file.seekp(0);
file.write((char*) p_map_ptr, sizeof(*p_map_ptr));
file.close();
}
void loadData(unordered_map<int, int>* p_map_ptr) {
fstream file("data.bin", ios::in | ios::binary);
file.seekg(0);
file.read((char*) p_map_ptr, sizeof(*p_map_ptr));
file.close();
}
int main() {
unordered_map<int, int> map;
map[0] = 5;
saveData(&map);
map.clear();
loadData(&map);
cout << map[0];
}
解决方案
容器序列化是一个小问题,因为它是作为一个哈希表来实现的,它的实现有点复杂,从这张图unordered_map
你可以看出来。
在您的代码中,您应该unordered_map
有一个起始地址(char*) p_map_ptr
和一个固定的大小sizeof(*p_map_ptr)
并且具有连续的内存布局,这是错误的。
开始地址(char*) p_map_ptr
是unordered_map
的地址,它可能包含一个桶向量的地址,与元素的地址无关,元素存储在列表中,存储在桶中。
sizesizeof(*p_map_ptr)
只是unordered_map
的大小,不是所有元素的大小,如果我们改成它p_map_ptr->sizes() * sizeof(decltype(p_map_ptr)::value_type)
会得到所有元素的总大小,但是我们仍然不能使用这个大小来复制内存。由于内存布局std::unrodered_map
是分散的。
一个相当大的选择是使用boost 序列化:
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/unordered_map.hpp>
#include <fstream>
#include <iostream>
#include <unordered_map>
using namespace std;
void saveData(const unordered_map<int, int>& map,
const std::string& file = "data.bin") {
std::ofstream filestream(file);
boost::archive::binary_oarchive archive(filestream,
boost::archive::no_codecvt);
archive << map;
}
void loadData(unordered_map<int, int>* p_map_ptr,
const std::string& file = "data.bin") {
std::ifstream filestream(file);
boost::archive::binary_iarchive archive(filestream,
boost::archive::no_codecvt);
archive >> *p_map_ptr;
}
int main() {
unordered_map<int, int> map;
map[0] = 5;
map[1] = 6;
saveData(map);
map.clear();
loadData(&map);
cout << map[0];
}
要构建代码,我们需要添加一个链接标志,对于 Linux:-lboost_serialization
相关答案:要使用文本存档进行序列化和反序列化,它比此处的二进制存档更易于阅读,但性能较低。
推荐阅读
- android - Dagger 2 Injector 并使用 IntKey 绑定 IntoMap
- php - 1X5矩阵树结构PHP数组
- node.js - 在NodeJS中检测一个数字是否可以被100整除
- python - 需要登录时使用 python 从 cloud.google.com 下载公共文件
- windows - 如何缩短 Git Bash 提示 (Windows)
- sql - 奇怪的 SQL 远程查询
- python - Python 子进程 - 在创建的新命令提示符中运行第二个命令
- swift - Firestore 收集侦听器大量读取
- php - 如何获取实例类名
- c# - BackgroundService 结束他分配的任务后会发生什么?