c++c++11linked-listintrusive-containersforward-list

std::forward_list -- erasing with a stored iterator


I'm trying to keep a global list of a particular (base) class's instances so that I can track them down by iterating through this global list at any time.

I believe the most proper way to address this is with an intrusive list. I have heard that one can encounter these creatures by digging into the Linux kernel, for example.

In the situation where I'm in, I don't really need such guarantees of performance, and using intrusive lists will complicate matters somewhat for me.

Here's what I've got so far to implement this concept of a class that knows about all of its instances.

class A {
    static std::forward_list<A*> globallist;
    std::forward_list<A*>::iterator listhandle;
public:
    A() {
        globallist.push_front(this);
        listhandle = globallist.begin();
    }
    virtual ~A() {
        globallist.erase_after(...);  // problem
    }
};

The problem is that there is no forward_list::erase(), and it really does not appear like saving globallist.before_begin() in the ctor would do me much good. I'm never supposed to dereference before_begin()'s iterator. Will it actually hold on to the position? If I save out before_begin's iterator, and then push_front() a new item, that iterator is probably still not capable of being dereferenced, but will it be serviceable for sending to erase_after()?


Solution

  • forward_list is a singly linked list. To remove a node in the middle of that, you must have a pointer to previous node, somehow. For example, you could do something like this:

    class A {
        static std::forward_list<A*> globallist;
        std::forward_list<A*>::iterator prev_node;
    public:
        A() {
            A* old_head = globallist.front();
            globallist.push_front(this);
            prev_node = globallist.before_begin();
            old_head->prev_node = globallist.begin();
        }
    };
    

    The case of pushing the first element into an empty list, as well as the removal logic, are left as an exercise for the reader (when removing, copy your prev_node to the next node's prev_node).

    Or, just use std::list and avoid all this trouble.