Container changes in C++11

The recently approved C++11 standard brings a lot of welcome changes to C++ that modernize the language a little bit. Among the many changes, we find that containers have received some special love.

Initialization

C++ was long behind modern languages when it came to initializing containers. While you could do

[cpp]int a[] = {1, 2, 3};[/cpp]

for simple arrays, things tended to get more verbose for more complex containers:

[cpp]
vector v;
v.push_back(“One”);
v.push_back(“Two”);
v.push_back(“Three”);
[/cpp]

C++11 has introduced an easier, simpler way to initialize this:

[cpp]
vector v = {“One”, “Two”, “Three”};
[/cpp]

The effects of the changes are even better for things like maps, which could get cumbersome quickly:

[cpp]
map<string, vector > m;
vector v1;
v1.push_back(“A”);
v1.push_back(“B”);
v1.push_back(“C”);

vector v2;
v2.push_back(“A”);
v2.push_back(“B”);
v2.push_back(“C”);

m[“One”] = v1;
m[“Two”] = v2;
[/cpp]

This can now be expressed as:

[cpp]
map<string, vector> m = One,

                             {"Two", {"Z", "Y", "X"}}};

[/cpp]

Much simpler and in line with most modern languages. As an aside, there’s another change in C++11 that would be easy to miss in the code above. The declaration

[cpp]map<string, vector> m;[/cpp]

was illegal until now due to » always being evaluated to the right-shift operator; a space would always be required, like

[cpp]map<string, vector > m[/cpp]

No longer the case.

Iterating

Iterating through containers was also inconvenient. Iterating the simple vector v above:

[cpp]
for (vector::iterator i = v.begin();

 i != v.end(); i++)
cout << i << endl;[/cpp]

Modern languages have long had some foreach equivalent that allowed us easier ways to iterate through these structures without having to explicitly worry about iterators types. C++11 is finally catching up:

[cpp]
for (string s : v)

cout << s << endl;

[/cpp]

As well, C++11 brings in a new keyword, auto, that will evaluate to a type in compile-type. So instead of

[cpp]
for (map<string, vector >::iterator i = m.begin();

 i != m.end(); i++) {

[/cpp]

we can now write

[cpp]
for (auto i = m.begin(); i != m.end(); i++) {
[/cpp]

and auto will evaluate to map<string, vector>::iterator.

Combining these changes, we move from the horrendous

[cpp]
for (map<string, vector >::iterator i = m.begin();

 i != m.end(); i++)
for (vector<string>::iterator j = i->second.begin();
     j != i->second.end(); j++)
    cout << i->first << ': ' << *j << endl;

[/cpp]

to the much simpler

[cpp]
for (auto i : m)

for (auto j : i.second)
    cout << i.first << ': ' << j << endl;

[/cpp]

Not bad.

C++11 support varies a lot from compiler to compiler, but all of the changes above are already supported in the latest versions of GCC, LLVM, and MSVC compilers.

Roberto Selbach
Roberto Selbach
Software Engineer

Ever-learning gopher at HashiCorp.