将 sparse_hash_map<char *const, int> 序列化到文件时出现问题

problems when I serialize sparse_hash_map<char *const, int> into file

这是我将 sparse_hash_map(char *const, int) 序列化到文件中的代码,注意 map.key 类型是 char *const,这是必需的(如果不是,编译器会报告未找到匹配的函数)。这就是出现问题的地方,因为我无法将内存分配给类型为 char *const 的变量,我如何才能在为它分配足够的内存之前将数据从序列化文件读取到 map.key 中?或者,除了这个之外,还有什么方法可以序列化 sparse_hash_map(char *const, int) 吗?

#include <iostream>
#include <sparsehash/sparse_hash_map>
using google::sparse_hash_map;      // namespace where class lives by default

using namespace std;

#define SIZE 13

struct CharPointerToIntSerializer {
  bool operator()(FILE* fp, std::pair<char * const, int>* value) const {
    // this can't be done, since value->first is of type 'char *const'
    // value->first = realloc(value->first, SIZE);
    if (fread(const_cast<char *>(value->first), 1, SIZE, fp) != 1) {
      return false;
    }

    if (fread(&(value->second), sizeof(value->second), 1, fp) != 1)
      return false;
    return true;
  }

  bool operator()(FILE* fp, const std::pair<char * const, int>& value) const {
    if (fwrite(value.first, 1, SIZE, fp) != 1)
      return false;

    if (fwrite(&value.second, sizeof(value.second), 1, fp) != 1)
      return false;
    return true;
  }
};

int main(){
  sparse_hash_map<char*, int> old_map,new_map;
  char *p1, *p2;
  p1 = (char *) malloc(SIZE);
  p2 = (char *) malloc(SIZE);
  strcpy(p1, "hello");
  strcpy(p2, "world");
  old_map[p1] = 1;
  old_map[p2] = 2;

  FILE* fp = fopen("hashtable.txt", "w");
  old_map.serialize(CharPointerToIntSerializer(), fp);
  // cout << old_map[p1] << endl;
  // cout << old_map[p2] << endl;
  fclose(fp);

  FILE* fp_in = fopen("hashtable.txt", "r");
  new_map.unserialize(CharPointerToIntSerializer(), fp_in);
  fclose(fp_in);
  assert(old_map == new_map);
  cout << new_map[p2] << endl;
}

这个程序可以编译,但是当我 运行 它时,它告诉我 "segmentation fault 11",并且 gdb 调试结果显示 "memcpy.S: No such file or directory",任何帮助将不胜感激! :)

首先回答 OP 关于 char * 真的那么糟糕的问题。

char * 与 std::string 相比会大大增加您的工作量。首先,不需要 mallocfree(顺便说一句,你没有做 free)。调整大小和调整大小是为您完成的。事实上,除非您使用指向 std::string 的指针,否则所有内存管理都会为您处理。 strcpy 并且随之而来的所有超限检查变为 =。如果需要,拆分、搜索和排序功能都是内置的。非常灵巧的小家伙们,std::strings.

作为容器密钥,您可能无法控制销毁逻辑。该对将被销毁,指针将随之销毁,但指向的内存仍将存在并且需要 freed,但您不再拥有可以调用 [=13] 的指针=].

您可以 free 在配对的析构函数触发并销毁指针之前的内存,但是您必须保护代码中销毁配对的所有点。当它可以为您完成时,为什么还要忍受散布在您程序中的头痛和跟踪代码?

问题

bool operator()(FILE* fp, std::pair<char * const, int>* value) const {
  // this can't be done, since value->first is of type 'char *const'
  // value->first = realloc(value->first, SIZE);
  if (fread(const_cast<char *>(value->first), 1, SIZE, fp) != 1) {
    return false;
  }

  if (fread(&(value->second), sizeof(value->second), 1, fp) != 1)
    return false;
  return true;
}

如您所述,您无法为 value->first 分配存储空间,因此 fread(const_cast<char *>(value->first), 1, SIZE, fp) 注定失败,除非您在首次创建配对时为 value->first 分配存储空间。如果您没有创建该对,则 value->first 指向 NULL 的可能性非常大。 fread 为 NULL 会繁荣。

接下来,当映射删除该对时,free谁是 char*?可能是内存泄漏。

问题随字符串一起消失,但您不想直接 fread 到字符串中。

你会想要更像

  char buf[size+1]; // +1 for null char
  int len = fread(buf, 1, SIZE, fp)
  if (len != 1) {
    return false;
  }
  buf[len] = '0\'; //terminate string with null
  value->first = buf;

Buf 分配在堆栈上,因此当它超出范围时它将被销毁,但此时它已被复制到字符串中。如果 buf 以保证为 null 的方式存储,则您可能不需要 null buf。

错误消息"memcpy.S: No such file or directory" 是GDB 试图显示失败的行,但无法找到包含memcpy 函数的源文件。段错误值得担心,源文件丢失,不是那么重要。该错误出现在调用 memcpy 之前的某处。检查堆栈跟踪以找到您的最后一行代码并从那里开始调查。