C++11: Feel the New Language

886 views
761 views

Published on

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
886
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
36
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

C++11: Feel the New Language

  1. 1. C++11Feel the new language
  2. 2. Where is C++?
  3. 3. What’s special about C++ Lightweight abstraction programming language B.Stroustrup• Build abstractions at little or no cost• Without sacrificing transparency• Without sacrificing performance• Pay as you go• Dive under the hood whenever you like
  4. 4. What makes C++11 differentDirect language support for powerful patterns E.g. Lambdas, move semanticsIncorporating best practices and libs into STL – Smart pointers, regular expressions E.g.Catch-up with the modern hardware – Multi-threaded memory model E.g.Shifting programming style to higher level – Naked pointers are persona non grata E.g.
  5. 5. What is a lightweight abstraction?goto: – Low-level (machine thinking) – Welcome to spaghetti codeif-then-else, while-loop, loop-until: – Abstracise goto – High-level, meaningful (human thinking) – Composable, self-contained building blocks – Transparent – No performance cost – Can still use goto if necessary
  6. 6. Smart pointers and Resource Handling
  7. 7. Lightweight abstraction: memoryRaw pointers (T*): – Low-level (machine thinking) – Welcome to crashes and memory leaksSmart pointers (unique_ptr<T>, shared_ptr<T>): – Abstracise raw pointers – High-level, meaningful (human thinking) – Transparent – Little or no performance cost – Can still use raw pointers if necessary
  8. 8. Raw pointers (or HANDLEs)widget *getWidget();void foo(){ widget *pw = getWidget(); // Don’t know if we’re sharing the widget with someone else // Don’t know if we must delete pw when done // Have to manually take care about exception-safety …}
  9. 9. unique_ptr<T>• Ownership semantics• Think auto_ptr<T> done right• Calls delete or delete[] in destructor• Movable, but not copyable (see Move Semantics later)• No runtime overhead#include <memory>std::unique_ptr<widget> getWidget();void foo(){ std::unique_ptr<widget> pw{ getWidget() }; // The widget is exclusively ours // We can’t accidentally share it // It will be deleted automatically and exception-safe}
  10. 10. shared_ptr<T>• Ref-counting semantics shared_ptr<T> T• Last one calls delete in destructor• Transparent and deterministic shared_ptr<T>• Ref-counting and synchronization overhead• Use make_shared to reduce overhead shared_ptr<T> counter control block• Use weak_ptr to break cycles#include <memory>std::shared_ptr<widget> getWidget();void foo(){ std::shared_ptr<widget> pw{ getWidget() }; // The widget may be shared // We don’t own it so we don’t care about deleting it}
  11. 11. Resource Acquisition is Initializationvoid f(){ database *pdb = open_database("mydb"); … // What if we return or throw here? close_database(pdb);}class DBConnection{private: database *_pdb;public: explicit DBConnection(const char *name) : pdb(open_database(dbname)) {} ~DBConnection() { close_database(pdb); }}void f(){ DBConnection dbc("mydb"); … // The db connection is guaranteed to close properly}
  12. 12. Resource Acquisition is Initialization• GC in other languages only handles one resource - memory• RAII in C++ has been around for over a decade• C++11 encourages its use as default• Smart pointers help building RAII around legacy interfaces• Move semantics makes passing resources around cheap
  13. 13. Tradeoff That Isn’t
  14. 14. What’s wrong with low-level?• Unsafe? – Yes• Tedious? – Yes• Gets in the way of DRY? – Yes• Best performance? – No. May even make it worse Low-level programming is a powerful and complex tool, but it doesn’t guarantee you any advantage unless used properly.
  15. 15. Move Semantics
  16. 16. Value semantics as copy semantics• Value semantics traditionally means copy-semantics• Which means object gets copied when travels from one place to another• Which makes returning an object from a function expensive Matrix operator+( const Matrix& a, const Matrix& b ) { Matrix r; // Loop with r[i,j] = a[i,j]+b[i,j] return r; // Copying happens here – expensive }• Which requires ugly workarounds void operator+( const Matrix& a, const Matrix& b, Matrix& r ) { // Loop with r[i,j] = a[i,j]+b[i,j] }
  17. 17. Move constructor (and =)template <typename T> class Matrix{private: unsigned int m; // Number of rows unsigned int n; // Number of columns T *pelems; // Pointer to an array of m*n elementspublic: … // Copy constructor Matrix( const Matrix& other ) : m(other.m), n(other.n) { pelems = new T[m*n]; memcpy( pelems, other.pelems, m*n*sizeof(T) ); } // Move constructor Matrix( Matrix&& other ) { pelems = other.pelems; other.pelems = nullptr; } ~Matrix(){ delete[] pelems; }};
  18. 18. Move semantics Matrix m = a * transpose(b) + c * inv(d);• Readable• Efficient• Safe• Meaningful• Backward-compatible• Fully supported by STL
  19. 19. Rvalue references Matrix( const Matrix& other ); // const lvalue ref Matrix( Matrix&& other ); // non-const rvalue ref• The right function is selected through overload resolution• Rvalue reference is preferred when called with rvalue• Non-constness of the rvalue reference allows to modify the rvalue• Bonus: perfect forwarding
  20. 20. Copy or Move?• Implicit Matrix f( const Matrix& a ) { Matrix r(a); // copy: a can be used below, don’t mess with it … return r; // move: r is on its last leg }• Explicit Matrix f() { Matrix e{ {1,0}, {0,1} }; Matrix r( std::move(e) ); // forced move: e is zombie now and … // using it would be a bad idea }
  21. 21. Lambdas λ
  22. 22. Life before lambdas#include <vector>#include <algorithm>#include <iostream>using namespace std;struct DivisibilityPredicateFunctor{ int m_d; DivisibilityPredicate( int d ) : m_d(d) {} bool operator()( int n ) const { return n % m_d == 0; }};void OutputFunction( int n ){ cout << n << endl;};vector<int> remove_multiples( vector<int> v, int d ){ vector<int> r; remove_copy_if( begin(v), end(v), back_inserter(r), DivisibilityPredicateFunctor(d) ); return r;}void main(){ vector<int> v; int array[] = {0,1,2,3,4,5,6,7,8,9}; for( int i = 0; i < sizeof array/sizeof *array; ++i ) v.push_back( array[i] ); vector<int> m = remove_multiples( v, 3 ); for_each( begin(m), end(m), OutputFunction );}
  23. 23. Life in C++11#include <vector>#include <algorithm>#include <iostream>using namespace std;vector<int> remove_multiples( vector<int> v, int d ){ vector<int> r; remove_copy_if( begin(v), end(v), back_inserter(r), [=](int n){ return n % d == 0; } ); return r;}void main(){ vector<int> m = remove_multiples( {0,1,2,3,4,5,6,7,8,9}, 3 ); for_each( begin(m), end(m), [](int n){ cout << n << endl; } );}
  24. 24. Lambdas• Without jumping through hoops now: – STL algorithms – Callbacks – Threading• Foundation for higher-level stuff: – Async programming – Functional programmingC++ flavor: you have fine-grained control overenvironment capture.
  25. 25. Lambda anatomy return type lambda introducer captured variable [=] (int n) -> int { return n % d == 0; } parameter listcapture list body
  26. 26. Lambda physiology • For each lambda compiler generates a class struct CompilerGeneratedFunctor {[d](int n)->bool int m_d;{ CompilerGeneratedFunctor(int d) : m_d(d) {} bool operator()(int n) const return n % d == 0; {} return n % m_d == 0; } }; • Specifying lambda instantiates an object • Invoking lambda calls the object’s operator() • Everything is easily inlinable
  27. 27. Lambda physiology • Lambda with empty capture list is just a function[](int n)->bool bool CompilerGeneratedFunction(int n){ { return n % 2 == 0; return n % 2 == 0; }} • Inlining is even easier
  28. 28. Variable captureBy value By reference Mix[=] [&] [=, &x, &y][x, y, z] [&x, &y, &z] [&, x, y]
  29. 29. Recommended watchinghttp://channel9.msdn.com/Events/GoingNative/GoingNative-2012

×