Sometimes, after you have used a special library or other special programming tool for a job, you forget about it because you don’t have that specific use case anymore. Boost’s multi_index container could fall in this category because you don’t have to hold data in memory with the need to access it by different keys all the time.
Therefore, this post is intended to be a reminder for c++ programmers that there exists this pretty cool thing called boost::multi_index_container and that you can use it in more situations than you would think at first.
(If you’re already using it on a regular basis you may stop here, jump directly to the comments and tell us about your typical use cases.)
I remember when I discovered boost::multi_index_container I found it quite intimidating at first sight. All those templates that are used in sometimes weird ways can trigger that feeling if you are not a template metaprogramming specialist (i.e. haven’t yet read Andrei Alexandrescu’s book “Modern C++ Design” ).
But if you look at it after you fought your way through the documentation and after your unit test is green that tests your first example, it doesn’t look that complicated anymore.
My latest use case for boost::multi_index_container was data objects that should be sorted by two different date-times. (For dates and times we use boost::date_time, of course). At first, the requirement was to store the objects sorted by one date time. I used a std::set for that with a custom comparator. Everything was fine.
With changing requirements it became necessary to retrieve objects by another date time, too. I started to use another std::set with a different comparator but then I remembered that there was some cool container somewhere in boost for which you can define multiple indices ….
After I had set it up with the two date time indices, the code also looked much cleaner because in order to update one object with a new time stamp I could just call container->replace(…) instead of fiddling around with the std::set.
Furthermore, I noticed that setting up a boost::multi_index_container with a specific key makes it much clearer what you intend with this data structure than using a std::set with a custom comparator. It is not that much more typing effort, and you can practice template metaprogramming a little bit 🙂
Let’s compare the two implementations:
#include <boost/shared_ptr.hpp> #include <boost/date_time/posix_time/posix_time.hpp> using boost::posix_time::ptime; // objects of this class should be stored class MyDataClass { public: const ptime& getUpdateTime() const; const ptime& getDataChangedTime() const; private: ptime _updateTimestamp; ptime _dataChangedTimestamp; }; typedef boost::shared_ptr<MyDataClass> MyDataClassPtr;
Now the definition of a multi index container:
#include <boost/multi_index_container.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/mem_fun.hpp> using namespace boost::multi_index; typedef multi_index_container < MyDataClassPtr, indexed_by < ordered_non_unique < const_mem_fun<MyDataClass, const ptime&, &MyDataClass::getUpdateTime> > > > MyDataClassContainer;
compared to std::set:
#include <set> // we need a comparator first struct MyDataClassComparatorByUpdateTime { bool operator() (const MyDataClassPtr& lhs, const MyDataClassPtr& rhs) const { return lhs->getUpdateTime() < rhs->getUpdateTime(); } }; typedef std::multiset<MyDataClassPtr, MyDataClassComparatorByUpdateTime> MyDataClassSetByUpdateTime;
What I like is that the typedef for the multi index container reads almost like a sentence. Besides, it is purely declarative (as long as you get away without custom key extractors), whereas with std::multiset you have to implement the comparator.
In addition to being a reminder, I hope this post also serves as motivation to get to know boost::multi_index_container and to make it a part of your toolbox. If you still have fears of contact, start small by replacing usages of std::set/multiset.
Hi, regarding use cases – some time ago I found that facebook’s folly library utilizes boost multi_index – TimeoutQueue class. Worth checking out
Thanks great poost