html5-img
1 / 53

Writing Modern C++

Writing Modern C++. Marc Grégoire Software Architect marc.gregoire@nuonsoft.com http://www.nuonsoft.com / http://www.nuonsoft.com/blog /. Agenda. Why C++? C++ Core Value Modern C++ Resources. Why C++?. C++ is having a kind of renaissance People are coming back to C++

admon
Télécharger la présentation

Writing Modern C++

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Writing Modern C++ Marc Grégoire Software Architect marc.gregoire@nuonsoft.com http://www.nuonsoft.com/ http://www.nuonsoft.com/blog/

  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<FILE> 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_tnum, size_tsize,int (*comparator) (constvoid *, const void *)); // Call it as follows for a double arrayqsort(myDoubleArray, n, sizeof(double), compare_double); Number of bytes in one element Number of elements in memory Memory to be sorted Comparison function to compare two elements

  15. Things to Unlearn 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) Use C++ algorithms like std::sort() Example: std::sort(begin(vec), end(vec));

  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: howtocapture variables fromenclosing scope • parameters(optional): parameter list, justlike a function • mutable(optional): variables capturedby-value are const, mutablemakesthem non-const • exception_specification(optional): = throw list • return_type(optional): the return type; ifomitted • If the body of the lambda expression is of the following form:{ return expression; }the type of expression will become the return_typeof the lambda expression.  • Otherwise the return_type is void

  18. Lambda Expressions • Basic example: int main() { []{cout << "Hello from Lambda" << endl;}(); } • Capture block • [ ]capturesnothing • [=] 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++ T* shared_ptr<T> new make_shared auto type deduction Old circle* p = newcircle(42); vector<shape*> vw = load_shapes(); for (vector<circle*>::iterator i = vw.begin(); i != vw.end(); ++i) { if (*i && **i == *p)cout << **i << " is a match\n";} for (vector<circle*>::iterator i = vw.begin(); i != vw.end(); ++i) {delete *i;} delete p; New auto p = make_shared<circle>(42); vector<shared_ptr<shape>> vw = load_shapes(); for_each(begin(vw), end(vw), [&](shared_ptr<circle>& s) { if (s && *s == *p)cout << *s << " is a match\n"; } ); for/while/do std:: algorithms[&] lambda functions no need for “delete” automatic lifetime management exception-safe 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[] 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<MyObject> p = new MyObject(); // ...} • Or, even better, just do:void foo(){MyObjectobj; // ...}

  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 lifetime automatically tied to enclosing scope constructs w, including the w.g gadget member void f() { widget w; /* ... */ w.draw(); /* ... */ } class widget { private: gadget g; public: void draw();}; Automatic destruction and deallocation for w and w.g lifetime automatically tied to enclosing object no leak, exception safe Automatic exception safety, as if “finally { w.g.dispose(); w.dispose(); }”

  27. The Heap and Smart Pointers class gadget; class widget {private:shared_ptr<gadget> g;}; class gadget {private:weak_ptr<widget> 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 unique ownership node ownsits children no leak, exception safe class node { vector<unique_ptr<node>> children;node* parent;/* … */ public: node( node* parent_) : parent(parent_) {children.push_back( new node(…) ); /* … */ }}; 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.”— BjarneStroustrup

  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 Your default container: vector compact, efficient: cache-friendly, prefetcher-friendly set: Like map, but only keys • 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 fixed size vector Key-value-pairs: map (tree) or unordered_map (hash)

  32. Containers - Examples vector<string> v;v.push_back("Geddy Lee"); array<int, 50> a; a[0] = 123; map<string, string> phone;phone["Alex Lifeson"] = "+1 (416) 555-1212"; multimap<string, string> phone;phone["Neil Peart"] = "+1 (416) 555-1212";phone["Neil Peart"] = "+1 (905) 555-1234"; unordered_map<string, string> phone;phone["Alex Lifeson"] = "+1 (416) 555-1212"; unordered_multimap<string, string> phone;phone["Neil Peart"] = "+1 (416) 555-1212";phone["Neil Peart"] = "+1 (905) 555-1234";

  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 for/while/do std:: algorithms[&] lambda functions arbitrary length lambda bodies, just put the loop body inside the lambda 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_eachto visit each element find_ifto find a match prefer non-member begin()/end()

  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<int,int> 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 algorithmauto minmax = minmax_element(begin(vec), end(vec));cout << "Min = " << *(minmax.first) << " and Max = " << *(minmax.second) << endl; • // Find the first subsequence of two consecutive 8sauto it = search_n(begin(vec), end(vec), 2, 8); • // all_of()vector<int> vec= {1,1,1,1};bool b = all_of(begin(vec), end(vec), [](inti){return i == 1;});

  40. Algorithms • Numerical processing algorithms examples • // Calculate arithmetic mean of the elements in a vectordouble sum = accumulate(begin(vec), end(vec), 0);double avg = sum / vec.size(); • // Calculate geometric mean of the elements in a vectordouble 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 5 6 7 8 9 10 11 12 13 14vector<int> 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 vectortransform(begin(vec), end(vec), begin(vec), [](inti){return i + 100;}); • // Replace all values < 0 with 0replace_if(begin(vec), end(vec), [](inti){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 elementsstrings.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? vector<string> 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+(constHugeMatrix&,constHugeMatrix&); hm3 = hm1+hm2; set<widget>load_huge_data() { set<widget> ret; // … load data and populate ret … return ret;} widgets = load_huge_data(); efficient, no deep copy-shuffle (just 1.5M ptr/len assignments) efficient, no deep copy no need for “heap allocation + return a pointer” workaround efficient, no extra copies

  48. Move Semantics – How To Implement? class my_class {unique_ptr<BigHugeData> 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"; }}; • Needs: • Move constructor • Move assignment operator check (if appropriate)

  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

More Related