简体   繁体   中英

Store pointers to objects in multiple containers

For the sake of presenting my question, let's assume I have a set of pointers (same type)

                                {p1, p2, ..., pn} 

I would like to store them in multiple containers as I need different access strategy to access them. Suppose I want to store them in two containers, linked list and a hash table. For linked list, I have the order and for hash table I have the fast access. Now, the problem is that if I remove a pointer from one container, I'll need to remember to remove from other container. This makes the code hard to maintain. So the question is that are there other patterns or data structures to manage situation like this? Would smart pointer help here?

If I understand correctly, you want to link your containers so that removing from one removes from all. I don't think this is directly possible. Possible solutions:

  • re-design whole object architecture, so pointer is not in many containers.
  • Use Boost Multi-index Containers Library to achieve all features you want in one container.
  • Use a map key instead of direct pointer to track objects, and keep the pointer itself in one map.
  • use std::weak_ptr so you can check if item has been deleted somewhere else, and turn it to std::shared_ptr while it is used (you need one container to have "master" std::shared_ptr to keep object around when not used)
  • create function/method/class to delete objects, which knows all containers, so you don't forget accidentally, when all deletion is in one place.

Why don't you create your own class which contains the both std::list and std::unordred_map and provide accessing functions and provide removal functions in a way that you can access them linearly with the list and randomly with the unordred_map , and the deletion will be deleting from both containers and insertion will insert to both. ( kind of a wrapper class :P )

Also you can consider about using std::map , and providing it a comparison function which will always keep your data structure ordered in the desired way and also you can randomly access the elements with log N access time.

As usually, try to isolate this logic to make things easier to support. Some small class with safe public interface (sorry, I didn't compile this, it is just a pseudocode).

template<class Id, Ptr>
class Store
{
public:
   void add(Id id, Ptr ptr)
   {
      m_ptrs.insert(ptr);
      m_ptrById.insert(std::make_pair(id, ptr));
   }

   void remove(Ptr ptr)
   {
      // remove in sync as well
   }

private:
   std::list<Ptr> m_ptrs;
   std::map<Id, Ptr> m_ptrById;
};

Then use Store for keeping your pointers in sync.

If I understand your problem correctly, you are less concern with memory management (new/delete issue) and more concern with the actual "book keeping" of which element is valid or not.

So, I was thinking of wrapping each point with a "reference counter"

 template< class Point >
 class BookKeeping {
 public:
     enum { LIST_REF = 0x01,
            HASH_REF = 0x02 };
     BookKeeping( const Point& p ): m_p(p), m_refCout( 0x3 ) {} // assume object created in both containers
     bool isValid() const { return m_refCount == 0x3; } // not "freed" from any container
     void remove( unsigned int from ) { m_refCount = m_refCount & ! from ; }
 private:
     Point m_p;
     unsigned int m_refCount;
 };

See the answer (the only one, by now) to this similar question . In that case a deque is proposed instead of a list , since the OP only wanted to insert/remove at the ends of the sequence.

Anyway, you might prefer to use the Boost Multi-index Containers Library .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM