On 2014-11-27 I gave a talk about C++ and new features introduced with C++11: these are the talk notes. See C++11 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.
[...]
C++ secret cultist protip
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; });
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;
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.
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);
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");
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.