Reputation: 477
I'm looking for ideas to implement a templatized sequence container data structure which can beat the performance of std::vector
in as many features as possible and potentially perform much faster. It should support the following:
operator[]
)What would be some good ways to implement such a structure in C++?
Upvotes: 1
Views: 1601
Reputation: 23122
You generally be pretty sure that the STL implementations of all containers tend to be very good at the range of tasks they were designed for. That is to say, you're unlikely to be able to build a container that is as robust as std::vector
and quicker for all applications. However, generally speaking, it is almost always possible to beat a generic tool when optimizing for a specific application.
First, let's think about what a vector
actually is. You can think of it as a pointer to a c-style array, except that its elements are stored on the heap. Unlike a c array, it also provides a bunch of methods that make it a little bit more convenient to manipulate. But like a c-array, all of it's data is stored contiguously in memory, so lookups are extremely cheap, but changing its size may require the entire array to be shifted elsewhere in memory to make room for the new elements.
Here are some ideas for how you could do each of the things you're asking for better than a vanilla std::vector
:
O(N)
for many containers, and certainly for a vector
(because you need to iterate through all elements to find the lowest). You can make it O(1)
, or very close to free, by simply keeping the smallest element at all times, and only updating it when the container is changed.boost
's stable vector will do this for you). Keep in mind that this make lookup more expensive, because you now need to dereference the pointer, so whether you want to do this will depend on your application. If you know the number of elements you are going to insert, std::vector
provides the reserve
method which preallocates some memory for you, but what it doesn't do is allow you to decide how the size of the allocated memory grows. So if your application warrants lots of push_back
operations without enough information to intelligently call reserve
, you might be able to beat the standard std::vector
implementation by tailoring the growth function of your container to your particular needs. Another option is using a linked list (e.g. std::list
), which will beat an std::vector
in insertions for larger containers. However, the cost here is that lookup (see 4.) will now become vastly slower (O(N)
instead of O(1)
for vectors), so you're unlikely to want to go down this path unless you plan to do more insertions/erasures than lookups.std::vector
in this regard is by making sure your data is in the cache when you try to access it. This is because lookup for a vector is essentially an array lookup, which is really just some pointer arithmetic and a pointer dereference. If you don't access your vector often you might be able to squeeze out a few clock cycles by using a custom allocator (see boost
pools) and placing your pool close to the stack pointer.I stopped writing mainly because there are dozens of ways in which you could approach this problem.
At the end of the day, this is probably more of an exercise in teaching you that the implementation of std::vector
is likely to be extremely efficient for most compilers. All of these suggestions are essentially micro-optimizations (which are the root of all evil), so please don't blindly apply these in important code, as they're highly likely to end up costing you a lot of time and headache.
However, that's not to say you shouldn't tinker and learn for yourself, so by all means go ahead and try to beat it for your application and let us know how you go! Good luck :)
Upvotes: 2