Better access to associative containers

  • Post category:C++ / Snippets

Another before and after snippet is related to accessing associative containers.
I recently saw some code and was reminded of an example by presented at CppCon 2014 Talk by Chandler Carruth.
Below is the original code:

std::unordered_map<int, MyClass> myContainer;
// ... 
void invokePattern1(const int key)
{
    myContainer[key].invokeA();
    myContainer[key].invokeB();
    myContainer[key].invokeC();
    myContainer[key].invokeD();
}

Improved version

After I watched the talk I felt the need to improve it to this:

std::unordered_map<int, MyClass> myContainer;
// ... 
void invokePattern1(const int key)
{
    auto& accessedElement = myContainer[key];
    accessedElement.invokeA();
    accessedElement.invokeB();
    accessedElement.invokeC();
    accessedElement.invokeD();
}

By just accessing the container once we reduce the number of calls to the containers [ ] operator. This reduces the amount of computation we have to do per invokePattern call.

Why not make invokePatternA a member function?

You may think that a better way to restructure that would be to encapsulate the calls to the invoke member functions in one single invokePattern member function of MyClass all together:

void invokePattern1(const int key) // Possible improvement
{
    // Just forward the call to MyClass
    myContainer[key].invokePattern1();
}

But what if you need another pattern, that MyClass cannot know (and does not care) about right now:

void futurePattern(const int key)
{
    myContainer[key].invokeA();
    myContainer[key].invokeA();
    myContainer[key].invokeB();
    myContainer[key].invokeB();
}

The more functions can access private parts of a class, the greater its encapsulation. If you’d add another invokePattern1 member you would increase that number and decrease encapsulation.

Of course you could make all invokeA, B, C, D member private after you have written your new invokePattern1 member, but that will cause a change every time a caller might need a new pattern. That will drastically decrease the classes flexibility and is probably not what you want.

See a full explanation of why to not make the change from a non-member (non-friend!) function to a member function in Item 23 of Scott Meyer’s Effective C++.