Hacker News new | ask | show | jobs
by SamReidHughes 4189 days ago
You can also make these using this structure:

    template <class T>
    struct node { node<T> *next, *prev; };

    template <class T>
    struct intrusive_list : private node<T> { };
Your type foo then subclasses the node<foo> type, and in some places intrusive_list<foo> has to statically cast them back down.

This means you don't need that messy "T *owner;" pointer anywhere.

The downside is that if you want your type to be a member of multiple intrusive lists, you have to make spurious parent classes and inherit from those.

1 comments

One possible alternative is having your objects be members of "lists of slightly different type". For example,

    template <ptrdiff_t offset, class T>
    struct node {
        node<offset> *next, *prev;
        T& operator*() { return *(this-offset); }
    };
Maybe? It has been a while since I've written C++. I guess you have a big problem setting up your base class in a portable way, though, because the types of its member nodes depend on their offsets, and I don't think you can do that.

    class Foo {
        int data;
        node<offsetof(Foo, list1_elem), Foo> list1_elem;
        node<offsetof(Foo, list2_elem), Foo> list2_elem;
    };
:/
I'm not sure if that would work, because computing the offset of list1_elem could depend on the template instantiation of list1_elem because that could (ostensibly) affect the alignment. But you can drop the template altogether on the list element type and put the offsetof expression in the list type declaration. An example of that is linked by some other comment in this thread: http://www.codeofhonor.com/blog/avoiding-game-crashes-relate...

The base class option is, I think, best only for the case where you have only one kind of list you want the object to be part of.

Also your pointer should be cast to char before you do offsetof arithmetic on it.