【问题标题】:Linked list in allocated space?分配空间中的链表?
【发布时间】:2014-04-18 14:36:24
【问题描述】:

我希望这个问题不会在讨论中过于重视,而是在一个明确的答案上。

我在大学学习了 C 语言,并且刚刚开始编写我的第一个有用的程序(意思是没有规范)。我只是偶然发现了一个到目前为止我还没有处理过的问题,我认为他们在讲座中没有提到它:

当我分配可能会调整大小的内存时,我不应该存储指向该分配空间地址的指针。因为当我重新分配时,空间可能会移动到不同的位置,这使得指向该区域的每个指针都毫无价值。这让我得出结论,我不能在空间内存储一个链表,每个元素都“生活”在这个空间的某个地方,因为重新分配可能会使所有的 'next' 和 'prev' 指针无效。

这是我从未遇到过的问题,这就是为什么我想问您是否有解决方案。具体来说:我有一个共享内存区域,并且想在其中存储我的所有数据,以便不同的进程可以在它上面工作。由于数据(字符串)会频繁添加和删除,并且必须按特定顺序排列,我认为链表是最好的方法。现在我意识到我不能这样做。还是我太盲目而看不到明显的解决方案?你会怎么做? (我不想将整个内容存储在文件中,它应该保留在(主)内存中)

感谢和最好的问候, 菲尔

【问题讨论】:

  • 通常你不会调整链表中的元素。您只需添加和删除独立元素。
  • @KerrekSB:我认为他将节点存储在内存缓冲区中,他使用 realloc 调整大小。如果您想将节点存储在进程之间共享的内存缓冲区中,您会遇到类似的问题。
  • 如果您需要支持任意顺序的任意添加和删除,您最终将自己实现malloc。是否有一些移除模式可以用来让事情变得更简单?

标签: c++ c pointers linked-list alloc


【解决方案1】:

可以以牺牲简单性和性能为代价来完成。您不必将指针存储在共享内存中,而是必须存储 与区域开头的偏移量。然后,当您想要“取消引用”其中之一时,您可以将偏移量添加到指向共享区域的指针。

为避免错误,我会为此创建一个特殊类型,具体取决于您使用的实际语言

C

 //seriously, this is one situation where I would find a global justified
 region_ptr region;

 //store these instead of pointers inside the memory region
 struct node_offset {ptrdiff_t offset};

 //used to get a temporary pointer from an offset in a region
 //the pointer is invalidated when the memory is reallocated
 //the pointer cannot be stored in the region
 node* get_node_ptr(node_offset offset) 
 {return (node*)((char*)region+offset.offset);}

 //used to get an offset from a pointer in a region
 //store offsets in the region, not pointers
 node_offset set_node_ptr(region* r, node* offset) 
 {node_offset o = {(char*)offset.offset-(char*)region}; return o;}

C++

 //seriously, this is one situation where I would find a global justified
 region_ptr region;

 //store these in the memory region
 //but you can pretend they're actual pointers
 template<class T>
 struct offset_ptr { 
     offset_ptr() : offset(0) {}

     T* get() const {return (T*)((char*)region + offset);}
     void set(T* ptr) {offset = (char*)ptr - (char*)region;}

     offset_ptr(T* ptr) {set(ptr);}
     offset_ptr& operator=(T* ptr) {set(ptr); return *this;}
     operator T*() const {return get();}
     T* operator->() const {return get();}
     T& operator*() const {return *get();}

 private:
     ptrdiff_t offset;
 };

 template<class T>
 struct offset_delete {
     typedef offset_ptr<T> pointer;
     void operator()(offset_ptr<T> ptr) const {ptr->~T();}
 };
 //std::unique_ptr<node, offset_delete<node>> node_ptr;

【讨论】:

    【解决方案2】:

    另一种与Mooing Duck建议的偏移方法非常相似的方法是数组和数组索引。

    如果每个列表元素的大小相同,则声明一个指向这些列表元素数组的指针。将该指针设置为内存区域的开头。存储数组偏移量而不是 prev 和 next 节点的指针。现在编译器会为您添加偏移量。

    【讨论】:

      猜你喜欢
      • 2016-03-07
      • 2022-01-02
      • 1970-01-01
      • 2013-06-16
      • 1970-01-01
      • 2015-04-30
      • 2011-07-06
      • 1970-01-01
      • 2020-12-22
      相关资源
      最近更新 更多