Question

I hope this question won't be weighted too much on discussion but on a clear answer.

I learned C at university and just started to write my first useful program (meaning without a specification). I just stumbled upon an issue which I hadn't dealt with so far, and I think they did not mention it in the lecture:

When I allocate memory that is likely to be resized, I should not store pointers to addresses of this allocated space. Because when I reallocate, the space might be moved to a differend location, which makes every pointer to this region worthless. This brings me to the conclusion that I cannot store a linked list inside the space, with every element 'living' somewhere in this space, since reallocating might invalidate all of the 'next' and 'prev' pointers.

This is an issue I never came across, that's why I wanted to ask you if there is some solution to this. Specifically: I have a shared memory region and want to store all my data in it, so that different processes can work on it. Since the data (strings) will be added and removed frequently and must be in a specific order, I thought a linked list would be the best way to go. Now I've realized I can't do it this way. Or am I just too blind to see the obvious solution? How would you go about this? (I don't want to store the whole thing in a file, it should stay in (main)memory)

thanks and best regards, phil

Was it helpful?

Solution

It can be done at the expense of simplicity and therefore performance. Instead of storing pointers inside the shared memory, you have to store offsets from the beginning of the region instead. Then, when you want to "dereference" one of these, you add the offset to the pointer-to-the-shared-region.

To avoid errors, I would make a special type for this, depending on the actual language you're using

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;

OTHER TIPS

Another method which is very similar to the offset method suggested by Mooing Duck is an array and array indexes.

If every list element is the same size then declare a pointer to an array of these list elements. Set that pointer to the beginning of the memory region. Store array offsets instead of pointers for prev and next nodes. Now the compiler takes care of adding the offsets for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top