The larger gain is explained better and comes simply from stack allocation of some structures (which live in a simple array, not a linked list or hash table).
The larger gain is explained better and comes simply from stack allocation of some structures (which live in a simple array, not a linked list or hash table).
I wonder why this wasn't the original design; I've seen the "two-allocate" method a few times in other code and it's always seemed rather silly to allocate that separate little structure just to point to the things you're linking together anyway, so I'm curious how that way of doing it became somewhat commonplace.
That use case is possible with the particular implementation that is now used by curl:
struct fileinfo {
struct curl_fileinfo info;
struct curl_llist_element list;
};
You can use the payload (struct curl_fileinfo) outside of a list without incurring any overhead.I think one of your other points is more likely, or simply "it was fast enough and we went for more interesting features than for such optimizations".
struct A {
int x, y;
};
struct B {
union {
struct A 2d;
struct { int x, y; };
}
int z;
};
...
struct B foo;
foo.x = foo.2d.y = foo.z = 0;
you can access x and y as members of B or A.And when you have a memory overwrite then your meta data is corrupted and you loose the complete list. I keep my meta data and payload in two separate list for that very reason.
Arranging the code to "keep trucking" in case of spurious memory overwrites seems like setting it up to be hard to debug, and having programs run in some ill-defined state where some portion of data has been overwritten but nobody notices is just super-scary.