This is my attempt at a look at some of the features of C++11, and more importantly, describing some of the style changes in C++11 that will make programmers more productive and programs more efficient.
2. If you write C-style code, you’ll end
up with C-style bugs.
-- Bjarne Stroustrup
If you write Java-style code, you’ll
have Java-level performance.
http://yaserzt.com/ 1
3. C++98: First Standard
C++03: minor changes, mostly the standard
TR1
C++11
Larger and more complex
Leaner and meaner at the same time
http://yaserzt.com/ 2
4. C++ has no replacement if you want
total control
best performance/$
to take advantage of hardware (multicore, GPU, …)
to program the way you want
zero-overhead abstractions
http://yaserzt.com/ 3
5. Mixed-paradigm, statically-typed, compiled,
widespread, many libraries, YDPFWYDU,
works everywhere and with everything.
No ABI, tooling very complex.
Libraries don’t work together, complex and
vast, bad teachers, intimidating for beginners,
seems too verbose and low-level.
http://yaserzt.com/ 4
6. “Don’t break people’s code”
Oriented towards library-developers
Lower-cost abstractions
Easier for beginners (a little)
“If it can go into the Standard Library, do not
put it in the language”
http://yaserzt.com/ 5
8. What is the type of a + b?
Even if you don’t know, the compiler always does.
decltype(a + b) c;
Instead of double c;
auto instructs the compiler to infer type from
initializing expression, e.g.
auto foo = a * b + c * d;
auto bar =
new std::map<std::string, bool>;
http://yaserzt.com/ 7
9. Not always a convenience feature.
What’s the return type of
template <typename T, typename U>
??? Add (T const & a, U const & b)
{
return a + b;
}
One answer is decltype(T() + U())
▪ (not entirely correct)
The correct answer is decltype(a + b)
But that won’t compile.
http://yaserzt.com/ 8
10. That’s the motivation behind the new
function declaration syntax:
auto Fun (type1 p1, type2 p2, ...)
-> returntype;
The previous function then becomes:
template <typename T, typename U>
auto Add (T const & a, U const & b)
-> decltype(a + b);
http://yaserzt.com/ 9
11. Think of them as unnamed functions, written in the middle of
your code, plus much more.
[] (int a, int b) -> int {return a + b;}
Lambdas are far-reaching and far more complicated under
the hood, with many more features.
auto g =
[] (int a, int b) -> int {return a + b;};
int c = g(43, -1);
std::function<int (int, int)> h =
[] (int a, int b) -> int {return a + b;};
int d = h(41, 1);
http://yaserzt.com/ 10
13. class StupidCollection
{
std::vector<int> m_data;
public:
void apply (std::function<int (int)> f)
{
for (auto i = m_data.begin(), e = m_data.end(); i != e; ++i)
*i = f (*i);
}
template <typename Func>
void apply (Func f)
{
for (auto i = m_data.begin(), e = m_data.end(); i != e; ++i)
*i = f (*i);
}
};
http://yaserzt.com/ 12
14. C++ used to have a tendency to copy stuff around if
you weren’t paying attention!
What happens when we call this function?
vector<string> GenerateNames ()
{
return
vector<string>(50, string(100, '*'));
}
A whole lot of useless stuff are created and copied around.
All sorts of techniques and tricks to avoid those copies.
Hold that thought for a minute.
http://yaserzt.com/ 13
15. string s = string("Hello") + " " + "world.";
1. string (char const * that)
2. operator + (char const * that)
3. operator + (char const * that)
4. this ultimately called the copy c’tor string (string const &
that).
5. (Unrelated note) Allocations can be avoided with “Expression
Templates”.
C++11 introduces “rvalue references” to let you work with (kinda)
temporary objects.
Rvalue references are denoted with &&.
e.g. int && p = 3;
http://yaserzt.com/ 14
16. In situations where you used to copy the data
from an object into another object, if your first
object is an rvalue (i.e. temporary) now you can
“move” the data from that to this.
Two important usages of rvalue references are
“move construction” and “move assignment”.
e.g. string (string && that);// move c'tor
and string & operator = (string && that);
// move assignment
http://yaserzt.com/ 15
23. struct SomeClass
{
string s;
vector<int> v;
// WRONG! WRONG! WRONG!
// Doesn’t move, just copies.
SomeClass (SomeClass && that)
: s (that.s), v (that.v)
{}
SomeClass (SomeClass && that)
: s (std::move(that.s)), v (std::move(that.v))
{}
};
http://yaserzt.com/ 22
24. In principle, std::move should look like this:
template <typename T>
??? move (??? something)
{
return something;
}
What should the argument type be?
T&& ?
T& ?
Both? Neither?
We need to be able to pass in both lvalues and rvalues.
http://yaserzt.com/ 23
25. We can overload move() like this:
move (T && something)
move (T & something)
But that will lead to exponential explosion of overloads if the
function has more arguments.
“Reference collapse” rule in C++98:
int& & is collapsed to int&.
In C++11, the rules are: (in addition to the above)
int&& & is collapsed to int&.
int& && is collapsed to int&.
int&& && is collapsed to int&&.
http://yaserzt.com/ 24
26. Therefore, only the T&& version should be enough.
If you pass in an lvalue to our move, the actual argument
type will collapse into T&, which is what we want
(probably.)
So, move looks like this thus far:
template <typename T>
??? move (T && something)
{
return something;
}
http://yaserzt.com/ 25
27. Now, what is the return type?
T&& ?
It should be T&& in the end.
But if we declare it so, and move() is called on an
lvalue,
▪ then T will be SomeType&
▪ then T&& will be SomeType& &&
▪ then it will collapse into SomeType&
▪ then we will be returning an lvalue reference from move(),
which will prevent any moving at all.
We need a way to remove the & if T already has one.
http://yaserzt.com/ 26
28. We need a mechanism to map one type to another
In this case, to map T& and T&& to T, and T to T.
There is no simple way to describe the process, but
this is how it’s done:
template<typename T> struct RemoveReference
{
typedef T type;
};
With that, RemoveReference<int>::type will be
equivalent to int.
But we are not done.
http://yaserzt.com/ 27
29. Now we specialize:
template<typename T>
struct RemoveReference<T&>
{
typedef T type;
};
template<typename T>
struct RemoveReference<T &&>
{
typedef T type;
};
Now, RemoveReference<int &>::type will be int too.
http://yaserzt.com/ 28
30. Our move now has the correct signature:
template <typename T>
typename RemoveReference<T>::type &&
move (T && something)
{
return something;
}
But it’s not correct. That “something” in there is
an lvalue, remember?
http://yaserzt.com/ 29
31. …so we cast it to an rvalue reference:
template <typename T>
typename RemoveReference<T>::type &&
move (T && something)
{
return static_cast<
typename RemoveReference<T>::type &&
>
(something);
}
Hopefully, this is correct now!
http://yaserzt.com/ 30
32. Templates with variable number of arguments
For example
template <typename... Ts>
size_t log (int severity, char const * msg,
Ts&&... vs);
Remember the old way?
size_t log (int severity, char const * msg, ...);
Using va_list, va_start, va_arg and va_end in <cstdarg>
Or
#define LOG_ERROR(msg, ...)
log (SevError, msg, __VA_ARGS__)
http://yaserzt.com/ 31
33. Almost the same for classes:
template <typename... Ts>
class ManyParents
: Ts...
{
ManyParents ()
: Ts ()...
{}
};
Now these are valid:
ManyParents<A> a;
ManyParents<A, B> b;
http://yaserzt.com/ 32
34. template <typename T, typename... PTs>
T * Create (T * parent, PTs&&... ps)
{
T* ret = new T;
ret->create (parent, ps...);
return ret;
}
PTs and ps are not types, values, arrays, tuples or
initializer lists.
They are new “things”.
http://yaserzt.com/ 33
35. Rules of expansion are very interesting:
Ts... → T1,T2,…,Tn
Ts&&... → T1&&,…,Tn&&
A<Ts,U>... → A<T1,U>,…,A<Tn,U>
A<Ts,Us>... → A<T1,U1>,…,A<Tn,Un>
f(42, vs...) → f(42,v1,…,vn)
f(42, vs)... → f(42,v1),…,f(42,vn)
One more operation you can do:
size_t items = sizeof...(Ts); // or vs
http://yaserzt.com/ 34
36. Let’s implement the sizeof... operator as an example.
template <typename... Ts> struct CountOf;
template <> struct CountOf<>
{
enum { value = 0 };
};
template <typename T, typename... Ts>
struct CountOf
{
enum { value = CountOf<Ts...>::value + 1 };
};
Use CountOf like this:
size_t items = CountOf<Ts>::value;
http://yaserzt.com/ 35
38. Initializer lists (std::initializer_list<T>)
static_assert (expr, "message");
Delegating constructors
Member initialization in class declaration
Explicitly overriding inherited methods
Explicitly using or not using default methods
http://yaserzt.com/ 37
39. Functions, constructors and class members as
constexprs.
UTF8, UTF16, UTF32 and raw string literals
User-defined literals
Libraries for regular expressions, shared
pointers, threads , tuples, atomic operations,
working with the file system,… (mostly from
TR1 and Boost.)
http://yaserzt.com/ 38
40. Wikipedia article on C++11 at
http://en.wikipedia.org/wiki/C%2B%2B11
Scott Meyers, Herb Sutter and Andrei Alexandrescu –
C++ and Beyond (lectures and presentations)
Presentations by Bjarne Stroustrup and Stephan T.
Lavavej from Going Native 2012
Microsoft’s implementation of the C++11 Standard
Library (accompanying VC11 Beta)
C++11 published standard: ISO/IEC 14882:2011
A draft (similar to the published standard) is available at
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
http://yaserzt.com/ 39
41. If you have a shotgun, you don’t have to use it to kill mosquitoes.
But it’s a lot of fun!
Contact us at http://fanafzar.com/
And me at y@yaserzt.com
42. Hardware is the platform – everything else is
just cruft
Abstractions are necessary (d’oh!)
Good abstractions let you express more
Good abstractions let you declare intent
Good abstractions can increase performance
memcpy() vs. std::copy()
qsort()vs. std::sort()
http://yaserzt.com/ 41
43. class thread
{
public:
class id;
thread ();
template <class F, class... Args>
explicit thread (F&& f, Args&&... args);
~thread();
bool joinable() const;
void join();
void detach();
id get_id() const;
static unsigned int hardware_concurrency();
};
http://yaserzt.com/ 42