我希望这个问题不会在讨论中加权太多,而是在一个明确的答案上。
我在大学学习了C,并开始编写我的第一个有用的程序(意思是没有规范)。我偶然发现了一个迄今为止我没有处理过的问题,我认为他们没有在讲座中提到它:
当我分配可能调整大小的内存时,我不应该存储指向此分配空间地址的指针。因为当我重新分配时,空间可能会移动到不同的位置,这使得指向该区域的每个指针都毫无价值。这让我得出的结论是,我无法在空间中存储链表,每个元素都“居住”在这个空间的某个地方,因为重新分配可能会使所有“下一个”和“上一个”指针无效。
这是我从未遇到的问题,这就是为什么我想问你是否有解决方法。具体来说:我有一个共享内存区域,并希望将所有数据存储在其中,以便不同的进程可以对其进行操作。由于数据(字符串)将经常添加和删除,并且必须按特定顺序排列,因此我认为链接列表是最佳方式。现在我意识到我不能这样做。还是我太盲目看不到明显的解决方案?你会怎么做? (我不想把整个东西存放在一个文件中,它应该留在(主)内存中)
谢谢和最诚挚的问候, 菲尔
答案 0 :(得分:4)
可以以牺牲简单性和性能为代价来完成。不是将指针存储在共享内存中,而是必须存储来自区域开头的偏移量。然后,当你想要" dereference"其中之一,您将偏移量添加到指向共享区域的指针。
为避免错误,我会为此制作一种特殊类型,具体取决于您使用的实际语言
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;
答案 1 :(得分:1)
另一种与Mooing Duck建议的偏移方法非常相似的方法是数组和数组索引。
如果每个列表元素的大小相同,则声明指向这些列表元素数组的指针。将该指针设置为内存区域的开头。存储数组偏移量而不是prev和next节点的指针。现在编译器负责为你添加偏移量。