Blog Archive

Monday, September 8, 2014

C++11 improvements over C++03

Source:
http://www.cplusplus.com/articles/EzywvCM9/

About C++11

C++11 aka C++0x is the new standard of the C++ language, published in late 2011.
It supersedes the older C++03 standard, which was published in 2003.
Naturally, it brings improvements over the old standard, some of which this article will outline.

The revamped auto keyword

Verbosity is bad, mainly because it makes your code less clear.
So the auto keyword, a leftover from C, got a new meaning in C++11: automatic type deduction.

Example:
1
2
3
4
5
6
// the C++03 way
for (std::vector<int>::const_iterator ci = v.begin(); ci != v.end(); ++ci);

// the C++11 way
for (auto ci = v.cbegin(); ci != v.cend(); ++ci);
// notice the dedicated cbegin() and cend() member functions which return a const_iterator 



Bad example:
1
2
3
4
5
6
7
8
9
10
auto x = 10.0;
// if a newbie programmer changes `10.0' to `10', x becomes an integral type
// and code depending on it to be a floating point type will fail
// advice 1: use auto against verbosity, not consistency

for (auto i = 0ul; i < v.size(); ++i);
// this is just a clever way of writing `unsigned long int i=0'
// advice 2: don't use auto if you specify the type, it defeats its purpose

// advice 1+2=3: don't use auto with constants 



Range-based for()

Iterating over the contents of STL containers is a very common operation.
C++11 now provides a specialized for() which can iterate over anything that has a begin() and an end() member function, which return the expected iterators.
It also works on plain C arrays.

Example:
1
2
3
4
5
6
7
8
9
10
// the C++03 way
for (std::vector<int>::iterator i = v.begin(); i != v.end(); ++i);

// the C++11 way
for (int &item: v);
// item will become, in order, all the things stored in v
// notice how we're referencing the item, that allows us to change it

for (const int &item: v); // can't change item, we reference it for speed
for (int item: v); // can't change item, we're passing it by value 



Initializer lists

The containers in C++03 could not be initialized as "naturally" as good old C-style arrays. That has changed.

Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// C arrays
char   array1[] = {'A', 'B'};
double array2[] = {32.0, 6.003, -0.1};

// C++03 vectors

std::vector<char> cpp03vector1;
cpp03vector1.push_back('A');
cpp03vector1.push_back('B');

std::vector<double> cpp03vector2(3);
cpp03vector2[0] = 32.0;
cpp03vector2[1] = 6.003;
cpp03vector2[2] = -0.1;

// C++11 vectors
std::vector<char>   cpp11vector1 = {'A', 'B'};
std::vector<double> cpp11vector2 = {32.0, 6.003, -0.1};
// or...
std::vector<char>   cpp11vector3{'A', 'B'};
std::vector<double> cpp11vector4{32.0, 6.003, -0.1};
// notice that this works for all other containers as well, not just std::vector 



Initializer lists can also be used for more complex structures.

Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <map>
#include <string>
#include <vector>
#include <utility>

using namespace std;

map<string, vector<pair<string, int>>> name_languages_year {
    {"Dennis Ritchie",    {{"B",      1969}, {"C",        1973}}},
    {"Niklaus Wirth",     {{"Pascal", 1970}, {"Modula-2", 1973}, {"Oberon", 1986}}},
    {"Bjarne Stroustrup", {{"C++",    1983}}},
    {"Walter Bright",     {{"D",      1999}}}
};
// notice how the lists are nested to match the templates' parameters

cout << name_languages_year["Niklaus Wirth"].at(0).first << endl; // prints `Pascal'

// adds a new entry to the map
name_languages_year["John McCarthy"] = {
    {"Lisp", 1958}
};
// notice the lack of explicit types 



C++ arrays


This is more of an addition than an improvement, but I decided to include it in the article anyway.
C++11 provides std::array, which has the purpose of replacing C arrays. It is a fixed-sized, lightweight alternative to the dynamically-sized std::vector.

Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <array>

// C arrays
char  carray1[] = "Abc"; // caution, an unseen '\0' is added to the end
float carray2[] = {0.2f, 33.33f};

// C++ arrays
std::array<char, 3>  cpparray1{{'A', 'b', 'c'}};
std::array<float, 2> cpparray2{{0.2f, 33.33f}};
// observation 1: the size must be deducible at compile time
// observation 2: the array cannot be resized
// observation 3: the inner braces are due to the nature of initializer lists,
//  think of it as one list per template parameter

// array test drive: the old versus the new

std::cout << sizeof carray1 - 1; // -1 because of the extra '\0'
std::cout << sizeof carray2 / sizeof (float); // because number of elements != number of bytes
std::cout << cpparray1.size();
std::cout << cpparray2.size();

carray2[-5] = 0.1f; // do the moonwalk!
cpparray2.at(-5) = 0.1f; // throws std::out_of_range exception

// of course there are more reasons why C++ arrays are better than C arrays
// but this example code section is already too big... 



Minor fixes

C++03 had a bunch of minor glitches and design flaws which were fixed in C++11:
  • Things like set<vector<int>> finally compile.
    Notice the lack of space between the last two angle brackets.

  • std::string now has front() and back() member functions.

  • File streams now accept an std::string as filename.
    This means one less use for the ridiculous c_str() member function.

  • Easy conversion of numerical values to std::string is now possible through the use of the overloaded functions:
    string to_string(int)
    string to_string(float)
    string to_string(double)
    ...

Compiler support for C++11

... is not too bad. But give it a year or two to set.

The GNU C++ compiler requires the commandline parameter -std=c++0x to compile C++11 code.

Microsoft Visual Studio 2010 has partial support for C++11 features, out of the box.
Microsoft Visual Studio 201x (v11) will still only have partial support for C++11 features.

No comments:

Post a Comment