The beauty of containers in C++11

The beauty of containers in C++11

Containers for storing data are one of many great features of the C++ Standard Library. Despite their advantages, to initialize them, and to loop over them was not always easy. Fortunately, the C++11 standard has made life easier, as I will explain below with examples. Disclaimer: this information has been known to C++ programmers for years, but is only slowly finding its way into our field of science.

The example below shows the initialization of a std::vector of the std::string type, and a loop over the vector to print its elements. Especially the loop, which has to define a const_iterator to get read-only access to the elements of a std::vector<std::string> container, is not easy to understand for the novice (scientific) programmer.

#include <vector>
#include <string>
#include <iostream>

int main()
{
    std::vector<std::string> numbers;
    numbers.push_back("one");
    numbers.push_back("two");
    numbers.push_back("three");

    for (std::vector<std::string>::const_iterator it=numbers.begin(); it != numbers.end(); ++it)
        std::cout << *it <<std::endl;

    return 0;
}

Even within the old standard, the piece of code above can be simplified by the declaration of a typedef as an alias for the container type.

int main()
{
    typedef std::vector<std::string> vs;
    vs numbers;
    numbers.push_back("one");
    numbers.push_back("two");
    numbers.push_back("three");

    for (vs::const_iterator it=numbers.begin(); it != numbers.end(); ++it)
        std::cout << *it <<std::endl;

    return 0;
}

With the C++11 standard (and as we speak, the new C++14 is being implemented in the latest versions of the major compilers), the initialization of a std::vector, as well as looping over its elements, can be greatly simplified as the example below shows.

#include <vector>
#include <string>
#include <iostream>

int main()
{
    std::vector<std::string> numbers = {"one", "two", "three"};

    for (const auto& s : numbers)
        std::cout << s << std::endl;

    return 0;
}

In the initialization, we make use of a so-called initializer list that passes its elements into a specialized constructor that inserts the elements one-by-one into the container.

The range-based for loop, in combination with the new auto specifier is another great feature. auto is able to deduct the type of variable s based on the container type of numbers. Note that s is a const reference, which is the fastest way to provide read-only access to container elements.

C++11 provides great opportunities to simplify C++-based scientific codes. Therefore, we are gradually introducing C++11 elements into MicroHH.