使用 Fstream 序列化无序映射

Serialization of Unordered Map Using Fstream

我需要序列化无序地图。下面的方法使用 fstream 以二进制方式读写数据到 map 中。但是,在清除地图并将其重新加载后,它会打印 0 而不是 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它是作为哈希表实现的,它的实现有些复杂,你可以从这个picture.

中一窥究竟

在您的代码中,您希望 unordered_map 具有起始地址 (char*) p_map_ptr 和固定大小 sizeof(*p_map_ptr) 并且具有连续的内存布局,这是错误的。

起始地址(char*) p_map_ptrunordered_map的地址,可能是一个bucket vector的地址,与元素地址无关,元素存放在链表中存储在存储桶中。

大小sizeof(*p_map_ptr)只是unordered_map的大小,不是所有元素的大小,如果我们把它改成p_map_ptr->sizes() * sizeof(decltype(p_map_ptr)::value_type)它会得到所有元素的总大小,但是我们仍然不能使用这个大小来复制内存。由于std::unrodered_map的内存布局是分散的

一个相当大的选择是使用 boost serialization:

#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

相关答案:要使用 进行序列化和反序列化,它比此处的二进制存档更具可读性但性能较低。