Presentation is loading. Please wait.

Presentation is loading. Please wait.

Writing Modern C++ Marc Grégoire Software Architect April 3 rd 2012.

Similar presentations


Presentation on theme: "Writing Modern C++ Marc Grégoire Software Architect April 3 rd 2012."— Presentation transcript:

1 Writing Modern C++ Marc Grégoire Software Architect April 3 rd 2012

2 Agenda  Why C++?  C++ Core Value  Modern C++  Resources

3 Why C++?  C++ is having a kind of renaissance  People are coming back to C++  Main reason: performance / €  You want to use the hardware as efficient as possible and squeeze the most out of it  Mobile devices: have limited power, use it efficiently  Datacenters: reducing power requirements directly results in saving money

4 C++ Core Value  Efficient abstraction  Strong abstraction: Type-safe OO and templates for powerful modeling, without sacrificing control and efficiency  Full control over code execution and memory: you can always express what you want to do you can always control memory and data layout exactly, if you want to  Pay-as-you go efficiency no mandatory overheads, don’t pay for what you don’t use Example: just because C++ supports virtual functions, you don’t pay a penalty for their support if you don’t use them

5 C++ Core Value  Cross platform, cross compiler, cross operating system  Performance very important “It’s incredibly important for C++ to be the language of performance. If there is a language lower than C++ and that has more performance, we didn’t do our job as a C++ community.” – Herb Sutter

6 C++ Core Value “The going word at Facebook is that ‘ reasonably written C++ code just runs fast,’ which underscores the enormous effort spent at optimizing PHP and Java code. Paradoxically, C++ code is more difficult to write than in other languages, but efficient code is a lot easier.” – Andrei Alexandrescu

7 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

8 Clean, Safe, Fast  Modern C++ code can be Clean, Safe, and Fast  Clean: express with minimal lines of code what you want to do, just as in other modern languages, resulting in easy to read and easy to understand code  Safe: modern C++ code is exception safe, memory safe, …  Fast: because it’s C++

9 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

10 Things to Unlearn  If you have used C++ before, you might have to unlearn a couple of things  Avoid low-level pointer manipulation and raw memory manipulation, in favor of higher level constructs  Do not use delete / delete [], use smart pointer; it’s:  Exceptions safe  Leak free  Deterministic, unlike garbage collectors

11 Things to Unlearn  Never do something like: FILE* f = fopen("data.ext", "w"); //... fclose(f);  Not exception safe!  Use RAII (Resource Acquisition Is Initialization)  Write a wrapper class: Constructor  opens the file Destructor  automatically closes the file  Often you can use std::shared_ptr, even for the above example Deterministic

12 Things to Unlearn  Instead of: FILE* f = fopen("data.ext", "w"); //... fclose(f);  Use: shared_ptr filePtr(fopen("data.ext", "w"), fclose);  Or write your own wrapper

13 Things to Unlearn  Avoid the old C-style algorithms, instead, use modern C++ algorithms

14 Things to Unlearn  For example, qsort() is a C-style algorithm with following signature: void qsort (void *base, size_t num, size_t size, int (*comparator) (const void *, const void *)); // Call it as follows for a double array qsort(myDoubleArray, n, sizeof(double), compare_double); Memory to be sorted Number of elements in memory Number of bytes in one element Comparison function to compare two elements

15 Things to Unlearn Use C++ algorithms like std::sort() Example: std::sort(begin(vec), end(vec)); Side-note: Even though std::sort() is a higher level construct, it’s faster than qsort by a large factor (not just a few percent)

16 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

17 Lambda Expressions  Syntax [capture_block](parameters) mutable exception_specification -> return_type { body }  capture block: how to capture variables from enclosing scope  parameters (optional): parameter list, just like a function  mutable (optional): variables captured by-value are const, mutable makes them non-const  exception_specification (optional): = throw list  return_type (optional): the return type; if omitted If the body of the lambda expression is of the following form: { return expression; } the type of expression will become the return_type of the lambda expression. Otherwise the return_type is void

18 Lambda Expressions  Basic example: int main() { []{cout << "Hello from Lambda" << endl;}(); }  Capture block  [ ] captures nothing  [=] captures all variables by value  [&] captures all variables by reference  [&x] captures only x by reference and nothing else  [x] captures only x by value and nothing else  [=, &x, &y] captures by value by default, except variables x and y, which are captured by reference  [&, x] captures by reference by default, except variable x, which is captured by value

19 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

20 Old C++ Versus New C++ Old circle* p = new circle(42); vector vw = load_shapes(); for (vector ::iterator i = vw.begin(); i != vw.end(); ++i) { if (*i && **i == *p) cout << **i << " is a match\n"; } for (vector ::iterator i = vw.begin(); i != vw.end(); ++i) { delete *i; } delete p; New auto p = make_shared (42); vector > vw = load_shapes(); for_each (begin(vw), end(vw), [&](shared_ptr & s) { if (s && *s == *p) cout << *s << " is a match\n"; } ); T*  shared_ptr new  make_shared no need for “delete” automatic lifetime management exception-safe for/while/do  std:: algorithms [&] lambda functions auto type deduction not exception-safe missing try/catch, __try/__finally

21 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

22 Avoid Delete  Write your code in such a way that there is never a need to use delete or delete[]

23 Avoid Delete  Don’t write code as follows: void foo() { MyObject* p = new MyObject(); //... delete p; }  It’s not exception safe!

24 Avoid Delete  Instead use shared_ptr or unique_ptr: void foo() { unique_ptr p = new MyObject(); //... }  Or, even better, just do: void foo() { MyObject obj; //... }

25 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

26 Automatic Lifetime  Automatic Lifetime = Efficient + Exception Safe class widget { private: gadget g; public: void draw(); }; void f() { widget w; /*... */ w.draw(); /*... */ } lifetime automatically tied to enclosing object no leak, exception safe lifetime automatically tied to enclosing scope constructs w, including the w.g gadget member Automatic destruction and deallocation for w and w.g Automatic exception safety, as if “finally { w.g.dispose(); w.dispose(); }”

27 The Heap and Smart Pointers class gadget; class widget { private: shared_ptr g; }; class gadget { private: weak_ptr w; }; shared ownership keeps gadget alive w/auto lifetime mgmt no leak, exception safe use weak_ptr to break reference-count cycles Side-note: Never use the old auto_ptr, it’s officially deprecated!

28 The Heap and Smart Pointers class node { vector > children; node* parent; /* … */ public: node( node* parent_) : parent(parent_) { children.push_back( new node(…) ); /* … */ } }; unique ownership node owns its children no leak, exception safe node observes its parent plain “new” should immediately initialize another object that owns it, example unique_ptr or shared_ptr

29 C++ and Garbage Collection “C++ is the best language for garbage collection principally because it creates less garbage.” — Bjarne Stroustrup

30 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

31 Containers  Avoid using C-style arrays  Instead use modern constructs such as STL containers  std::vector  std::array  std::map  std::unordered_map  std::multimap  std::unordered_multimap  std::set  std::unordered_set  std::multiset  std::unordered_multiset  std::list  std::forward_list Your default container: vector compact, efficient: cache- friendly, prefetcher-friendly fixed size vector Key-value-pairs: map (tree) or unordered_map (hash) set: Like map, but only keys

32 Containers - Examples vector v; v.push_back("Geddy Lee"); array a; a[0] = 123; map phone; phone["Alex Lifeson"] = "+1 (416) "; multimap phone; phone["Neil Peart"] = "+1 (416) "; phone["Neil Peart"] = "+1 (905) "; unordered_map phone; phone["Alex Lifeson"] = "+1 (416) "; unordered_multimap phone; phone["Neil Peart"] = "+1 (416) "; phone["Neil Peart"] = "+1 (905) ";

33 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

34 Loops Old for (auto i = v.begin(); i != v.end(); ++i) { /*... */ } auto i = v.begin(); for (; i != v.end(); ++i) { if (*i > x && *i < y) break; } New for_each (begin(v), end(v), [](string& s) { /*... */ } ); auto i = find_if(begin(v), end(v), [=](int i) { return i > x && i < y; } ); for/while/do  std:: algorithms [&] lambda functions for_each to visit each element find_if to find a match prefer non-member begin()/end() arbitrary length lambda bodies, just put the loop body inside the lambda

35 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

36 Algorithms  Don’t write your own algorithms unless you have a good reason or there is no standard algorithm for your use-case  Prefer standard algorithms  for_each(): Your default traversal algorithm transform() for not-in-place semantics  find_if(): Your default search algorithm  sort(), lower_bound(), …: Your default sorting and searching

37 Algorithms  Utility Algorithms  min(), max(), minmax(), swap()  minmax() example (C++11) int x1 = 2, x2 = 9, x3 = 3, x4 = 12; pair p1 = minmax({x1,x2,x3,x4}); cout << "Minmax of 4 elements is " << p1.first << "," << p1.second << endl;

38 Algorithms  Nonmodifying algorithms  Search algorithms find(), find_if(), find_if_not(), find_first_of(), search_n(), lower_bound(), upper_bound(), equal_range(), minmax_element(), all_of(), any_of(), none_of(), …  Numerical processing algorithms count(), count_if(), accumulate(), inner_product(), …  Comparison algorithms equal(), mismatch(), …  Operational algorithms for_each()

39 Algorithms  Nonmodifying algorithms examples  // Find min and max with 1 algorithm auto minmax = minmax_element(begin(vec), end(vec)); cout << "Min = " << *(minmax.first) << " and Max = " << *(minmax.second) << endl;  // Find the first subsequence of two consecutive 8s auto it = search_n(begin(vec), end(vec), 2, 8);  // all_of() vector vec = {1,1,1,1}; bool b = all_of(begin(vec), end(vec), [](int i){return i == 1;});

40 Algorithms  Numerical processing algorithms examples  // Calculate arithmetic mean of the elements in a vector double sum = accumulate(begin(vec), end(vec), 0); double avg = sum / vec.size();  // Calculate geometric mean of the elements in a vector double mult = accumulate(begin(vec), end(vec), 1, [](int num1, int num2){return num1 * num2;}); double geomean = pow(mult, 1.0 / vec.size());  // Create a vector with values vector vec(10); iota(begin(vec), end(vec), 5);

41 Algorithms  Modifying algorithms  transform(), copy(), copy_if(), move(), swap_ranges(), replace(), replace_if(), fill(), generate(), remove(), remove_if(), reverse(), rotate(), next_permutation(), …

42 Algorithms  Modifying algorithms examples  // Add 100 to each element in the vector transform(begin(vec), end(vec), begin(vec), [](int i){return i + 100;});  // Replace all values < 0 with 0 replace_if(begin(vec), end(vec), [](int i){return i < 0;}, 0);  // Remove all empty strings from a vector of strings // (Use remove-erase pattern!) auto it = remove_if(begin(strings), end(strings), [](const string& str){return str.empty();}); // erase the removed elements strings.erase(it, strings.end());

43 Algorithms  Sorting algorithms  sort(), stable_sort(), partial_sort(), merge(), …  Set algorithms  set_union(), set_intersection(), set_difference(), set_symmetric_difference(), …

44 Algorithms  Sorting algorithms example  If you want to do some binary search (lower_bound, upper_bound, equal_range, …), the sequence should be sorted first  Be sure to sort the sequence with the same predicate as you give to the search algorithm  Use named lambda, example: auto comp = [](const widget& w1, const widget& w2) { return w1.weight() < w2.weight(); } sort(begin(v), end(v), comp); auto i = lower_bound(begin(v), end(v), w, comp);

45 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

46 Move Semantics  C++11 Move Semantics increases efficiency and results in cleaner, easier to understand code  Why is move semantics useful?

47 Move Semantics – Why useful? set load_huge_data() { set ret; // … load data and populate ret … return ret; } widgets = load_huge_data(); vector v = AMillionStrings(); v.insert(begin(v)+v.size()/2, "tom"); v.insert(begin(v)+v.size()/2, "richard"); v.insert(begin(v)+v.size()/2, "harry"); HugeMatrix operator+( const HugeMatrix&, const HugeMatrix& ); hm3 = hm1+hm2; efficient, no deep copy no need for “heap allocation + return a pointer” workaround efficient, no deep copy-shuffle (just 1.5M ptr/len assignments) efficient, no extra copies

48 Move Semantics – How To Implement? class my_class { unique_ptr data; public: /*... */ my_class(my_class&& other) : data(move(other.data)) { } my_class& operator=(my_class&& other) { data = move(other.data); } void method() { if (!data) throw "moved-from object"; } }; check (if appropriate)  Needs:  Move constructor  Move assignment operator

49 Move Semantics – When?  If you have a copy constructor or copy assignment operator: Also implement move versions if they can be cheaper than a deep copy  Some types have only move versions, and no copy versions  For example: some types are naturally move-only, such as unique_ptr

50 Modern C++  Clean, Safe, Fast  Things to unlearn  Lambda expressions  Old C++ versus new C++  Avoid delete  Automatic lifetime (stack & heap)  Containers  Loops  Algorithms  Move semantics  Compile time encapsulation

51 Compile Time Encapsulation?  Use the Pimpl idiom to truly hide private members class my_class { //... all public and protected stuff goes here... private: class impl; unique_ptr pimpl;// opaque type here }; class my_class::impl {// defined privately here //... all private data and functions: all of these // can now change without recompiling callers... }; my_class::my_class() : pimpl(new impl) { /*... set impl values... */ }  Avoids rebuild cascades  Most appropriate for types used often my_class.h my_class.cpp

52 Resources  “Writing modern C++ code: how C++ has evolved over the years” – Herb Sutter   “GoingNative 2012, Keynote: C++ Style” – Bjarne Stroustrup  Bjarne-Stroustrup-Cpp11-Style Bjarne-Stroustrup-Cpp11-Style  Presentations from GoingNative 2012   Professional C++, 2 nd Edition 

53 Questions ? ? I would like to thank Herb Sutter from Microsoft for his permission to base this presentation on one that he wrote for Build 2011.

54 Widescreen Test Pattern (16:9) Aspect Ratio Test (Should appear circular) 16x9 4x3


Download ppt "Writing Modern C++ Marc Grégoire Software Architect April 3 rd 2012."

Similar presentations


Ads by Google