What do you do regarding collections? (Dynamic arrays, hashmaps)?
I don't do anything!
I use the most appropriate data-structure and minimal transformation necessary to get the work done. I use maths and higher-level tools to verify my designs but the implementation, when required to be soft-realtime needs to exploit as much mechanical sympathy from my target platform as possible.
You might be interested in https://dataorientedprogramming.wordpress.com
Cheers!
#define TYPE int
#include "list_template.h"
#undef TYPE
with `list_template.h` using TYPE wherever a data type would be needed and defining inline (C99) and/or static (C89) functions so that they can be redefined in multiple files (or have a dedicated C file that includes the above header with all data types and an additional macro that enables the implementation). This is basically sort of implementing templates in C.The void pointer approach is the simplest and most macro free (despite me using macros here, i'm a bit macro happy sometimes :-P) but at the same time you are limited to pointers. In practice i've found that most of the time this is enough, which is why i still haven't replaced that yet. But there are cases where i'd prefer to be able to have a list of structs instead of pointers to structs, both because it is simpler (no need to define a custom free function) and faster (less indirections), so i'll most likely replace that code with another approach (most likely the macro that defines the types, not the include header).
But if there is a single feature i'd like to see from C++ to C that would be templates, even if they are single depth. I don't even care about classes or the other stuff (classes are nice to have, but not necessary as long as the compiler can figure out that the template parameters to structs and functions with the same name refer to the same type when used together).
Strings have arbitrary sizes. How does pooling them together reduce fragmentation? Do they always come and go in groups?
This seems a little like cargo cultism. I wonder if any of these shops regularly measure the performance of their custom containers and compare with the standard library on a modern optimizing compiler and make a reasoned judgment that it's still currently worth the trade-offs to stick with their own stuff.
Part of it is also for cross-platform consistency. No chance for bugs caused by using a different stdlib, etc. This is worth it when a lot of the toolchains for consoles are arcane have the chicken/egg-ish problem of often having poor stl implementations since they expect everybody to implement their own.
I've been out of game dev for a while though. These days I'd expect using the C++ stdlib to be more common, and mallocs are faster now (although even if you're bundling e.g. jemalloc, I imagine you still get a substantial benefit from using pools or arenas in many cases).
As other comments have said though, the main reason it's used (and the reason I was interested even though I don't do games) is because the allocation story in the stdlib sucks.
(libstdc++'s vector looks sensible in this respect - a good decision on their part. Haven't looked at any other aspects of it though.)
At one point the contents of vectors were often inconvenient to examine in just about every debugger, because you'd have to type out some infeasibly long expression to get at them, "vec._Mybase._Myval._Myptr[0]", that kind of thing, which you could also fix by writing your own container and simply calling your pointer field something like "p". (Same goes for smart pointers.) Luckily this is much improved in the latest Visual Studio but it may still be an issue elsewhere.
Yes, while it wasn't often, we sometimes did benchmark tests to improve performance when bottlenecks were found, especially towards the game's release when we were focusing on optimizations. IIRC we did some minor changes in the dynamic array container and we rewrote the hashmap and hashset implementations. One of the programmers wrote a performance test comparing several algorithms both with synthetic and real data (from the case that created the bottleneck).
> compare with the standard library on a modern optimizing compiler and make a reasoned judgment that it's still currently worth the trade-offs to stick with their own stuff.
There are other reasons to use a custom container than just the pure performance of the container itself. One is using a different allocation scheme, as the example i gave in the grandparent post, another is to use a friendlier API (see `find` and friends) and add more features. An important one in our engine was support for the custom RTTI that was used for object serialization and the scripting language that also worked and exposed those directly - the container, the RTTI implementation and the scripting runtime had to have intimate knowledge about each other to work transparently (especially when the editor entered the picture, where you could create new entries, often objects but also sometimes structs or other data types, by editing the array directly in a property editor).
Of course not all engines do that and TBH most of the performance and memory related bits are more relevant to consoles than (desktop) PCs (the API friendliness and RTTI stuff are platform agnostic though :-P). At the previous gaming company i worked at, the engine used standard containers. Also AFAIK the engine used by the Two Worlds games also uses standard containers (based on some of their developers' comments).
Personally when i write C++ i implement my own containers not because of performance but simply because i dislike the STL API - for example i want to have "Find", "IndeOf", "Swap", etc methods in the container itself :-P. Sadly it seems that i'll also need to do the same if i decide to start working with D seriously since D's standard library seem to more or less copy the STL API style.
You don't know? Maybe you should find out before slinging around accusations of cargo cultism.
Related, Andrei Alexandrescu had a great talk about allocators in C++ a couple of years ago: https://www.youtube.com/watch?v=LIb3L4vKZ7U
Also related to the Orthodox C++, the same engine also ousted exceptions and RTTI. I'm not sure about the reason for exceptions, but C++'s RTTI was simply inadequate and instead it was replaced with a custom one made using macros (similarly to wxWidgets and MFC) that allowed automatic object serialization and reflection which was used for all saving and loading, exposing objects to the editor automatically with a common UI and exposing classes and objects to the (custom) scripting language with very little setup.
Interestingly most of the stuff the engine had to reinvent seem to be first class citizens in the D language. Also Andrei's allocators also seem to be available (experimentally) there too.
Personally i prefer plain old C (C89 even, although with a few commonly available or easily reproducible extras like stdint) because i see C++ as too complex for what it is worth. However D seems to provide more power with less complexity and more and more makes me want to try it, especially the new "better C" mode that DMD has got (which i think is somewhat the D equivalent to Orthodox C++ that is linked from the page).