Think about a builtin container_of

Recently, I attempted to implement an intrusive linked list library called uit, what makes it different is the use of a trick called mock_head, the mock_head converts the head node into the same type as the data node, and makes the code easier to write. Unfortunately, mock_head is implemented based on container_of, it’s an undefined behavior in C++ standard.
In the C language, container_of has been used by Linux for many years, and even today it still requires the use of -fno-strict-aliasing to avoid the UB. I think there is a design flaw in C++, please see the code below:

struct A { };

struct B : public A { };

struct C {
    A a;
};
A *a;
B *b;
C *c;

For B inheriting A(Virtual inheritance is not within the scope of this discussion):

  • upcast: a = static_cast<A *>(b);

  • downcast: b = static_cast<B *>(a);

For C containing A:

  • upcast: a = &c->a;

  • downcast: c = container_of(&C::a, a);

Whether static_cast, operator -> or constainer_of, they are essentially the same, it’s a pointer plus an offset. The container_of is not defined by the C++ standard. I think C++ compilers should implement a built-in function called __builtin_container_of, the result of the function should be the alias of the input. We can use it like __builtin_container_of<&C::a>(a) or container_cast<&C::a>(a).

There are some things I misunderstood, it’s not complicated to implement with inheritance, mock_head may not be UB in this way, container_of can no longer be needed, end of this topic.