C++11 - A Change in Style - v2.0

51
C++11 – A Change in Style Version 2.0 Yaser Zhian Fanafzar Game Studio IGDI, Workshop 01, August 2 nd , 2012

description

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.

Transcript of C++11 - A Change in Style - v2.0

Page 1: C++11 - A Change in Style - v2.0

C++11 – A Change in StyleVersion 2.0

Yaser ZhianFanafzar Game StudioIGDI, Workshop 01, August 2nd, 2012

Page 2: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 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.

Page 3: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 3

C++ History

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

Page 4: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 4

Why C++?

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

Page 5: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 5

C++: Il Buono, Il Brutto, Il Cattivo

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.

Page 6: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 6

C++11 Philosophy (sort of)

“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”

Page 7: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 7

A Hurried and Incomprehensive Tour of Some Features of an Arbitrary Subset of C++11

Page 8: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 8

auto and decltype (1/3)

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>;

Page 9: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 9

auto and decltype (2/3)

Not always a convenience feature. What’s the return type oftemplate <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.

Page 10: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 10

auto and decltype (3/3)

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);

Page 11: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 11

Lambdas (1/3)

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);

Page 12: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 12

Lambdas (2/3)

std::for_each (v.begin(), v.end(),[](float f) {std::cout << f << std::endl;}

);

int x = 7;std::for_each (v.begin(), v.end(),

[x](float & f) {f += x;});

float sum = 0.0f;std::for_each (v.begin(), v.end(),

[&sum](float f) {sum += f;});

Page 13: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 13

Lambdas (3/3)

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);}

};

Page 14: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 14

Rvalue References and Moving (1/A)

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 (){

returnvector<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.

Page 15: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 15

Rvalue References and Moving (2/A)

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;

Page 16: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 16

Rvalue References and Moving (3/A)

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

Page 17: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 17

Rvalue References and Moving (4/A)

template <typename T>class Matrix{private:

T * m_data;unsigned m_rows, m_columns;

public:Matrix (unsigned rows, unsigned columns);~Matrix ();Matrix (Matrix<T> const & that);template <typename U> Matrix (Matrix<U> const &

that);Matrix<T> & operator = (Matrix<T> const & that);Matrix (Matrix<T> && that);Matrix<T> & operator = (Matrix<T> && that);...

};

Page 18: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 18

Rvalue References and Moving (5/A)

template <typename T>class Matrix{

...unsigned rows () const;unsigned columns () const;unsigned size () const;T & operator () (unsigned row, unsigned col);// m(5, 7) =

0;T const & operator () (unsigned row, unsigned col) const;

template <typename U>auto operator + (Matrix<U> const & rhs) const

-> Matrix<decltype(T() + U())>;

template <typename U>auto operator * (Matrix<U> const & rhs) const

-> Matrix<decltype(T() * U() + T() * U())>;};

Page 19: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 19

Rvalue References and Moving (6/A)

Matrix (unsigned rows, unsigned columns) : m_rows (rows), m_columns (columns) , m_data (new T [rows * columns]){}

~Matrix (){ delete[] m_data;}

Matrix (Matrix<T> const & that) : m_rows (that.m_rows), m_columns (that.m_columns) , m_data (new T [that.m_rows * that.m_columns]){ std::copy ( that.m_data, that.m_data + (m_rows * m_columns), m_data );}

Page 20: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 20

Rvalue References and Moving (7/A)

Matrix<T> & operator = (Matrix<T> const & that){ if (this != &that) { m_rows = that.m_rows; m_columns = that.m_columns; T * new_data = new T [m_rows * m_columns]; std::copy ( that.m_data, that.m_data + (m_rows * m_columns), new_data ); delete[] m_data; m_data = new_data; } return *this;}

Page 21: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 21

Rvalue References and Moving (8/A)

Matrix (Matrix<T> && that) : m_rows (that.m_rows), m_columns (that.m_columns) , m_data (that.m_data){ that.m_rows = that.m_columns = 0; that.m_data = nullptr;}

Page 22: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 22

Rvalue References and Moving (9/A)

Matrix<T> & operator = (Matrix<T> && that){ if (this != &that) { T * old_data = m_data; m_rows = that.m_rows; m_columns = that.m_columns; m_data = that.data; that.m_rows = rhs.m_columns = 0; that.m_data = nullptr; delete[] old_data; } return *this;}

Page 23: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 23

Rvalue References and Moving (A/A)

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)) {}};

Page 24: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 24

std::move (1/8)

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.

Page 25: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 25

std::move (2/8)

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&&.

Page 26: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 26

std::move (3/8)

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;}

Page 27: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 27

std::move (4/8)

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.

Page 28: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 28

std::move (5/8)

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.

Page 29: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 29

std::move (6/8)

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.

Page 30: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 30

std::move (7/8)

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?

Page 31: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 31

std::move (8/8)

…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!

Page 32: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 32

Variadic Templates (1/5)

Templates with variable number of arguments For exampletemplate <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__)

Page 33: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 33

Variadic Templates (2/5)

Almost the same for classes: template <typename... Ts> class ManyParents : Ts... { ManyParents () : Ts ()... {} }; Now these are valid: ManyParents<A> a; ManyParents<A, B> b;

Page 34: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 34

Variadic Templates (3/5)

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”.

Page 35: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 35

Variadic Templates (4/5)

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

Page 36: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 36

Variadic Templates (5/5)

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;

Page 37: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 37

Using async and future

#include <future>string flip (string s) { reverse (s.begin(), s.end()); return s;}int main () { vector<future<string>> v; v.push_back (async ([] {return flip( " ,olleH");})); v.push_back (async ([] {return flip(" weN evarB");})); v.push_back (async ([] {return flip( "!dlroW");})); for (auto& i : v) cout << i.get(); cout << endl; return 0;}

Page 38: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 38

Other Assorted Features (1/2)

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

Page 39: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 39

Other Assorted Features (2/2)

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.)

Page 40: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 40

References (i.e. Source Material)

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

Page 41: C++11 - A Change in Style - v2.0

Any more questions?

Contact us at http://fanafzar.com/And me at [email protected]

If you have a shotgun, you don’t have to use it to kill mosquitoes.But it’s a lot of fun!

Page 42: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 42

Zero-cost Abstractions

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()

Page 43: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 43

Threads (1/2)

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();};

Page 44: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 44

Threads (2/2)

namespace this_thread{ thread::id get_id(); void yield (); void sleep_until (abs_time); void sleep_for (rel_time);}

Page 45: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 45

SFINAE

enable_if Type traits Sample std::copy

Page 46: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 46

Type Traits

Page 47: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 47

Resource Acquisition Is Initialization (1/2)

Page 48: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 48

Resource Acquisition Is Initialization (2/2)

Page 49: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 49

The Importance of Type Systems (1/3)

Page 50: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 50

The Importance of Type Systems (2/3)

Page 51: C++11 - A Change in Style - v2.0

http://yaserzt.com/ 51

The Importance of Type Systems (3/3)