Comment Re:C had no real successor (Score 1) 641
I used to be a "C" zealot who considered it unmanly to use other languages. I've got past that with age. C is simple, but it comes at the cost of having to do every last thing by hand. Even when it's unnecessary and the chance of making mistakes is high. After spending years on the nitty-gritty details, there comes a time when you have to ask: do I really need to implement the needed bits of a vector/list/set/map/hash or do I just use one that I know will work without any trouble. Chances are it's optimised better than my hand-rolled one would be. And it takes a few seconds to use, since I don't have to write all that wheel-reinventing code myself. I can focus on the problem I was trying to solve, rather than unnecessary groundwork.
Stuff like std::vector is often criticised by those who don't appreciate what it does. After optimisation, element access is as efficient as a C array, and the automatic memory management is no worse than what you'd need to do in C anyway. And it's type-safe and exception-safe. Same with std::string. This is also often more efficient than using the C string functions (though obviously can be less so if used badly). But it's safe and easy to use, which is the big win. How often have you screwed up C string manipulation. That's right, we all have, and even when it appears safe and working, it's often a disaster waiting to happen.
I'm replying to this because as I was reading through I was working on some code for work. We were using std::vector in a set of nested objects to keep track of their children using std::shared_ptr, and to allow cross-references with std::weak_ptr. Works just fine. But profiling showed that our usage patterns were suboptimal. We needed to keep track of objects by their insertion order (linear) but also needed to do fast lookups (set/rbtree). I could have hand-rolled a custom implementation, or made a custom container with embedded vector and set objects and logic to keep them synchronised. However, a little research and this was the solution:
template<typename T, template <typename ElementType> class Ptr>
struct indexed_container
{
typedef boost::multi_index_container<
Ptr<T>,
boost::multi_index::indexed_by<
boost::multi_index::random_access<>,
boost::multi_index::ordered_unique<boost::multi_index::identity<Ptr<T> >, std::owner_less<Ptr<T> > >
>
> type;
};
Total time from finding the problem to researching and creating this working solution (including converting the existing code to use it): 2 hours.
So now I can do indexed_container<foo, std::shared_ptr>::type c and get a custom container containing std::shared_ptr<foo> indexed by both insertion order and by pointer value. With C++11 I could use a templated typedef and also avoid the struct wrapper. And multi_index_container template is usable for all sorts of esoteric multiple-indexing with indexing on individual/multiple fields or with custom functors or whatever you like. Why would I want to reinvent that when there's a pre-canned implementation that just works. It certainly has intellectual value, but when you just need to get something done, the above is using the available tools to best effect. Imagine how many hundreds of lines of C the above typedef would require to reimplement from scratch. And how many man hours would it take to implement? It's just not worth doing that.