C++11 talk notes
On 2014-11-27 I gave a talk about C++ and new features introduced with C++11:
these are the talk notes. See
cxx11-talk-examples for the examples.
(note: I had to add
U+2063 INVISIBLE SEPARATOR to prevent
noreturn
statements to be misinterpreted by the blog formatter. If you copypaste the
code and encounter issues, you may want to delete the
noreturn statements and
retype them)
Overview of programming languages
It has to be as fast as possible, so interpreted languages are out.
You don't want to micro manage memory, so C is out.
You don't want to require programmers to have a degree, so C++ is out.
You want fast startup and not depend on a big runtime, so Java is out.
[...]
(Bram Moolenaar)
C++ secret cultist protip
Do not call up what you cannot put down.
C++ is a compiled language
It is now possible to use the keyword
constexpr to mark functions and objects
that can be used at
compile time:
/*
* constexpr tells the compiler that a variable or function can be evaluated at
* compile time.
*
* constexpr functions can also be run at run time, if they are called with
* values not known at compile time.
*
* See http://en.cppreference.com/w/cpp/language/constexpr for more nice examples
*
* It can be used to avoid using constants in code, and using instead functions
* for computing hardware bitfields or physical values, without losing in
* efficiency.
*/
#include <iostream>
using namespace std;
constexpr int factorial(int n)
return n <= 1 ? 1 : (n * factorial(n-1));
int main()
cout << "Compile time factorial of 6: " << factorial(6) << endl;
cout << "Enter a number: ";
int a;
cin >> a;
cout << "Run time factorial of " << a << ": " << factorial(a) << endl;
See also
this for more nice
examples. See
this
and
this
for further discussion.
Multiline strings
const char* code = R"--(
printf("foo\tbar\n");
return 0;
)--";
See
this.
C++ memory management protip
RAII: Resource Acquisition Is Instantiation
This is not new in C++11, but in my experience I have rarely seen it mentioned
in C++ learning material, and it does make a huge difference in my code.
See
this
and
this for
details.
Constructors and member initializer lists
Initializers in curly braces now have their own type:
std::initializer_list:
#include <string>
#include <iostream>
#include <unordered_set>
using namespace std;
// std::initializer_list< >
// will have as its value all the elements inside the curly braces
string join(initializer_list<string> strings)
string res;
for (auto str: strings)
if (!res.empty())
res += ", ";
res += str;
return res;
int main()
unordered_set<string> blacklist ".", "..", ".git", ".gitignore" ;
cout << join( "antani", "blinda" ) << endl;
See
this for
details, including the new uniform initialization trick of omitting parentesis
in constructors so that you can call normal constructors and
initializer_list
constructors with the same syntax, which looks like an interesting thing when
writing generic code in templates.
Type inference
I can now use
auto instead of a type to let the compiler automatically
compute the value of something I assign to:
auto i = 3 + 2;
// See also https://github.com/esseks/monicelli
vector<string> names "antani", "blinda", "supercazzola" ;
for (auto i = names.cbegin(); i != names.cend(); ++i)
cout << i;
template<typename T>
T frobble(const T& stuff)
// This will work whatever type is returned by stuff.read()
auto i = stuff.read();
//
See
this
for more details.
Range-based for loop
C++ now has an equivalent of the various foreach constructs found in several
interpreted languages!
for (auto i: list_of_stuff)
cout << i << endl;
for (auto n: 0,1,2,3,4,5 )
cout << n << endl;
// This construct:
for (auto i: stuff)
// If stuff is an array, it becomes:
for (i = stuff, i < stuff + sizeof(stuff) / sizeof(stuff[0]); ++i)
// If stuff has .begin() and .end() methods it becomes:
for (i = stuff.begin(); i != stuff.end(); ++i)
// Otherwise it becomes:
for (i = begin(stuff); i != end(stuff); ++i)
// And you can define begin() and end() functions for any type you
// want, at any time
See
this and
this
for details.
Lambda functions and expressions
Lambdas! Closures!
Something like this:
// JavaScript
var add = function(a, b) return a + b;
# Python
add = lambda a, b: a + b
Becomes this:
auto add = [](int a, int b) return a + b;
And something like this:
// JavaScript
var a = 0;
$.each([1, 2, 3, 4], function(idx, el) a += el );
Becomes this:
unsigned a = 0;
std::for_each( 1, 2, 3, 4 , [&a](int el) return a += el; );
See
this,
this
and
this.
Tuple types
C++ now has a
std::tuple type, that like in Python can be used to implement
functions that return multiple values:
tuple<int, string, vector<string>> parse_stuff()
return make_tuple(id, name, values);
string name; vector<string> values;
// std::ignore can be used to throw away a result
tie(ignore, name, values) = parse_stuff();
// std::tie can also be used to do other kind of
// multi-operations besides assignment:
return tie(a, b, c) < tie(a1, b1, c1);
// Is the same as:
if (a != a1) return a < a1;
if (b != b1) return b < b1;
return c < c1;
See
here,
here and
here.
Regular expressions
We now have regular expressions!
std::regex re(R"((\w+)\s+(\w+))");
string s("antani blinda");
smatch res;
if (regex_match(s, res, re))
cout << "OK " << res[1] << " -- " << res[2] << endl;
The syntax is ECMAScript by default and can be optionally changed to basic,
extended, awk, grep, or egrep.
See
here and
here.
General-purpose smart pointers
There is
std::unique_ptr to code memory ownership explicitly, and
std::shared_ptr as a reference counted pointer, and smart pointers can have
custom destructors:
unique_ptr<dirent, std::function<void(void*)>> dirbuf((dirent*)malloc(len), free);
See
here
and
here.
Miscellaneous other cool things
Standard attribute specifiers
string errno_str(int error)
char buf[256];
#if (_POSIX_C_SOURCE >= 200112L _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
strerror_r(errno, buf, 256);
string res(buf);
#else
string res(strerror_r(errno, buf, 256));
#endif
return res;
[ [noreturn]] void throw_libc_error(int error)
throw runtime_error(errno_str(error));
See
here.
Hash tables
See
here and look at the
new containers
unordered_set,
unordered_map,
unordered_multiset, and
unordered_multimap.
Multithreading
There is a standard threading model, with quite a bit of library support: see
here,
here,
here, and
here
for atomic data structures.
Variadic templates
Templates can now take variable number of arguments, and that opens
possibilities for interesting code generation, like implementing a generic,
type-safe printf statement, or something like this:
db.query(R"(
INSERT INTO table NAMES (id, name, description)
VALUES (?, ?, ?)
)", 4, "genio", "fantasia, intuizione, decisione, e velocit di esecuzione");
See
here and
here.
Essential tools
You need at least
g++ 4.8 or
clang 3.3 to have full C++11 support.
They will be both available in jessie, and for wheezy you can use the
nightly
clang packages repository. I cannot think of a good
excuse not to use
-Wall on new code.
scan-build from clang is
another nice resource for catching even more potential problems at compile
time.
valgrind is a great tool for runtime code analysis:
valgrind --tool=memcheck (the default) will check your program for wrong
memory accesses and memory leaks.
valgrind --tool=callgrind will trace
function calls for profiling, to be analyzed with
kcachegrind.
valgrind
--tool=helgrind can check multi-threaded programs for suspicious concurrent
memory accesse patterns.
And of course
gdb: a nice
trick with C++ is to issue
catch throw to get a breakpoint at the point
where an exception is being thrown.
help catch provides a list of other
interesting
catch examples.
Coredump tips:
ulimit -c to enable core dumps, triggering a core dump with
^\, opening a core with
gdb program core, and more details on
man 5 core.
An extra gdb tip, which is not related to C++ but helped me considerably
recently, is that
it can be attached to running python programs to get a live
Python traceback.