Easy to write, sure. But every time a developer has to look at it for the first time, they'll need to learn this hashmap's interface.
Do I need to manage memory? Does it manage memory? How do I iterate? How do I add a new key space without thrashing the original implementation and making it twice as complicated?
That's the biggest thing a standard interface gives you. Even if it's less performant and not well-designed, I'll take it.
The C++ containers are actually well-designed and performant so it's a no-brainer if you get to choose.
Almost forgot the type checking you get with C++. That's also a major factor.
> The C++ containers are actually well-designed and performant so it's a no-brainer if you get to choose.
The STL doesn't allow the containers to be "well-designed and performant" other than std::vector which is trivial. People do what they can, but there just isn't much to work with because random coincidences about the data structures that were in mind at the time are enshrined in the C++ standard as API features.
std::unordered_map is obliged to be a bucketed map. This is a poor choice, but it's not optional because it's enshrined in the API even though you probably don't (and shouldn't) actually rely on this. Lots of the good options are drop-in replacements for std::unordered_map... unless you really depend on it being a bucketed map.
The other important thing to know if you've been relying on the standard library is that the powerful need for backward compatibility means it's not going to give you a proper hash, which is important for a proper hash map. std::unordered_map doesn't care that the standard "hash" provided isn't, but if you use a hash map written by people who explicitly told you to use an actual hash it's going to exhibit jaw-droppingly bad performance until you do so.
std::unordered_map isn't worse than a reasonably competent person's "my first hash table" but it's disappointing how little better it is than that after decades.
As with all performance, if you aren't measuring then changes are just wanking, but if you are measuring you will almost certainly find that swapping out std::unordered_map is worth doing.
To be fair, if you ever rely on the default hash it's already safe to assume you don't care about performance. There's no good 'default' for all input.
I agree with all your points except "are actually well-designed and performant". I mean they perform well enough but when I write simple hashmaps that perform better than libstdc++ (yes with the same hash) anecdotally I don't have a lot of confidence.
- they implement way more features than an in-house implementation
- they need to support many types of hardware
A decent engineer can beat the std collections in a day on performance. But to do that in production over a decade with shifting requirements is a different ball game.
The one I cooked up was used to test some kind of game solver, so a 'large set' and it happily beat std::unordered_map, was a tiny bit slower than a Google hash map implementation.
But I do believe in edge cases, I'm sure there are some pathological edge cases (that don't usually matter, but deserve consideration).
I'm interested to know what 'way more features' are for hash maps/sets, because AFAIK C++ just supports the basic features you'd expect of the abstract data structure of a "map" with the algorithmic guarantees you'd expect from a hashmap.
And nothing I did was aimed at 'specific hardware' other than it vaguely benefitted from memory locality / avoiding thrashing the cache.
"Features" was probably the wrong word for me to use. What I was referring to is interface + customizability.
The STL map allows you to:
- specify the key/value types
- specify the equality predicate
- specify which hash function to use
- iterate over values
along with a host of other things that most users don't initially need but they might need in the future.
You could implement something that has feature parity in C++ or ideally find a battle-tested library that does.
Using C, however, you'd have to sacrifice type safety and possibly readability. Yes it can be done, and yes it can be done correctly. But it's tricky and difficult to ramp up on for the new developer. This is the one that you should be careful about adopting.
My philosophy is to use the STL containers because they're familiar and they're more than good enough for 99% of the use cases out there. Developer time has a premium, and this saves developer time.
If you need performance because you're constrained by CPU cycles or if you're running at scale (Google for example), by all means reach for something better.
Do I need to manage memory? Does it manage memory? How do I iterate? How do I add a new key space without thrashing the original implementation and making it twice as complicated?
That's the biggest thing a standard interface gives you. Even if it's less performant and not well-designed, I'll take it.
The C++ containers are actually well-designed and performant so it's a no-brainer if you get to choose.
Almost forgot the type checking you get with C++. That's also a major factor.