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).