我第一次尝试使用mmap存储一个包含大量数据的树对象。树类基本上包含一个指向Node类的根的指针,每个Node实例都有一个指向它的子节点的数组。我认为mmap正在做它应该做的事情,因为我可以访问树的常量成员,但是当我尝试访问指向root的指针时,我得到了一个段错误。
以下是创建具有根节点的树的方法:
int main(int argc, char *argv[])
{
Tree *map;
...
map = (Tree*)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
Node* root = new Node("data");
map->set_root(root);
...
}
以下是我访问树的方法:
int main(int argc, char *argv[])
{
int i;
int fd;
Tree *map;
fd = open(FILEPATH, O_RDONLY);
if (fd == -1) {
perror("Error opening file for reading");
exit(EXIT_FAILURE);
}
map = (Tree*)mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fd, 0);
if (map == MAP_FAILED) {
close(fd);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
Node* root = map->root();
cout << root->data();
...
root-&gt; data()的输出提供了段错误。任何人都可以给我一个暗示我错的地方吗?如果我没有明白我的问题,请说明。
提前致谢。
的Mads
答案 0 :(得分:5)
这是一团糟。在尝试尝试之前,您需要了解new
和delete
的工作原理。
从哪里开始。
map = (Tree*)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
这就是说,将那段内存视为Tree
,你没有在那段内存中构建一棵树。new
时,它会在内存中的某个位置分配一个Node
对象,并在树中保存一个指针,当它在其他地方重新打开时,指针不再有效你需要存储映射块中的所有节点......除了尝试理解自定义内存分配器之外,没有真正简单的答案。
答案 1 :(得分:0)
这不起作用。如果root()
是一个虚方法,那么你就会被清除,因为vtable指针指向当前进程中的方法。如果你不调用任何虚方法,可能工作,但它可能是未定义的行为。
在进程之间共享数据可能更好,而不是对象。让对象具有数据句柄,并保护对象的用户免受解码数据的细节。 Node* root = new Tree(memory_mapped_memory);
答案 2 :(得分:0)
当你致电mmap()
时,你基本上只是获得一块原始内存。因此,在不调用某种类型的未定义行为的情况下,您无法天真地取消引用指针map
...只需将从mmap()
返回的内存转换为类型Tree*
,就像您已经完成的那样在映射的内存中构造一个Tree
对象。
如果您希望在Tree
返回的内存中构造,甚至复制构造mmap
对象,您可能需要查看使用placement new
。例如,您可以执行以下操作:
void* map;
map = mmap(0, FILESIZE, PROT_READ, MAP_SHARED, fd, 0);
//...error checking
Tree* tree = new(map) Tree(); //placement new syntax
实际上,这将在Tree
返回的内存中默认构造一个mmap
对象,此时,您可以正确使用tree
指针变量以进一步添加节点到了树上。例如,现在可以调用以下代码而不创建未定义的行为:
Node* root = new Node("data");
tree->set_root(root);
使用placement new
,变量Tree
指向一个实际的tree
对象,您现在可以正确地取消引用该指针,以及与该对象关联的任何方法。
要记住的一个主要项目是,当使用placement new
时,您必须手动调用Tree
对象的析构函数,并且您必须手动释放您的内存。已通过mmap()
分配...您无法在delete
上致电Tree*
。