C is still, I have to imagine, the closest thing we have to a language available for all platforms that exist today, while C++ is heavily burdened with featuritis and Rust is limited in platform support.
Rust supports everything you are likely to see in the wild outside of highly, highly specialized applications (e.g. ancient mainframes, satellites from the 80s or 90s, etc.).
For God's sake, it's becoming increasingly difficult to justify writing code that takes into account CPU endianness, because all CPUs that are likely to run your code are little endian!
99% of ARM usage is done in little endian. all android & ios phones, all embedded boards that ship with linux, etc. are always configured in little endian.
Okay, assuming you're right, how much overhead is it to consider endianness? I've never had issues with it, unless I'm implementing something fully from scratch, and that's rare in a production environment.
People that deign network protocols love love big endian.
Which means on the software side you then have to swap everything from big endian to little endian. And you need to do that at the first opportunity so their big endian crap doesn't get loose in the rest of the code.
Sometimes there isn't C++ or Rust. Many embedded platforms only have a C compiler. And sometimes an existing codebase is written in C, and adding some C++ or Rust creates undesired new dependencies. See the Linux kernel debate on using those languages.
I favor the CTL over the STL anytime, because it compiles much faster, is much smaller, no indirect vtable calls, no bloated god objects, has no magic hooks attached, like dereferencing refs and ops, is clear on stack vs heap allocation.
The downside of course is that generics and iterators on those are a bit more troublesome, only compiler dependent goodies (mostly only clang, not gcc), like overloads or constexpr. C++ templates are ugly, and the STL is very buggy and limited. Also no security and no performance. They started on the wrong foot and had to keep it there.
Rust has an annoying syntax, but a much better library culture.
I haven't written the STL critic parts yet. The testsuite contains a lot of hints.
Major quirks: no proper allocation/resize upfront, when you know how big the resulting vector will be. Also not much help with bulk inserts. (Like a proper set join). The 3 STL's I tested massively overallocate.
Unordered containers allow ranges, iterators from some to some, whilst they are unordered by default. This begs for bugs.
Ranges are pairs? How broken is that? Iters need to be fat and ranges. Starting with a broken design upfront does not help.
Set and hashmaps have to use the slowest datastructures, because they considered better ones as too experimental. Hence no open hashmaps, just chained and rb trees. Their arguments of pointer and iterator stability is just an excuse after this decision. Everybody can work around that, and use open hashmaps and btree's just fine.
How about 3way comparison safety in set? It is not. They just found out recently.
No hashtable security, none. Slow, too big and insecure, how nice is that. 0 out if 3.
No sorted vectors, no small (stack) vectors.
No strings. Better than POSIX C, fine. But still no unicode support and identifier (names) support. How would you search for an international string? With accents and different normalization? You wont find it. Strings are not binary buffers.
Formally verified? Not, just 2 parts out of 20. This would have found the 3way compare problems, or their forward_list problems.
forward_list, one of the most basic datastructures, heavily used since the 50ies in Lisp. So why does lisp still has much better support for it than the STL? Cycle detection, length, shuffle, ...?
The manual free is of course annoying, agreed. Ditto the missing operator overloading, which is even worse. Or default args.
the gigabytes of STL-using C++ code that works just fine shows that most of them aren't serious issues. In ~15 years of C++ I have never had any issues with ranges being pairs, strings (though in my opinion string handling shouldn't be part of programming languages at all - they should just be treated as opaque binary blobs like you would pass to eg zlib or libpng), forward_list...
Also, all the interfaces of the STL being quite precise mean that
> Set and hashmaps have to use the slowest datastructures, because they considered better ones as too experimental. Hence no open hashmaps, just chained and rb trees. Their arguments of pointer and iterator stability is just an excuse after this decision. Everybody can work around that, and use open hashmaps and btree's just fine.
> No sorted vectors, no small (stack) vectors.
are non-issues: in my own software I can swap std::unordered_map, std::vector, etc... trivially for other containers only by changing their type and adding an include. e.g. in my codebase I have some boost::small_vector<>, boost::static_vector<>, pod_vector<>, flat_set, flat_map, and 4/5 different hash maps which are all chosen specifically for their performance characteristics on various use cases.
In particular if it was C instead, I would have had to change every single call to add, remove, iterate, etc. every time.