Writing Modern C Marc Grgoire Software Architect marc
- Slides: 53
Writing Modern C++ Marc Grégoire Software Architect marc. gregoire@nuonsoft. com http: //www. nuonsoft. com/blog/ April 3 rd 2012
Agenda Why C++? C++ Core Value Modern C++ Resources
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
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
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
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
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
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++
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
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 � Leak safe free � Deterministic, unlike garbage collectors
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 Deterministic you can use std: : shared_ptr, even for the above example
Things to Unlearn Instead of: FILE* f = fopen("data. ext", "w"); //. . . fclose(f); Use: shared_ptr<FILE> file. Ptr(fopen("data. ext", "w"), fclose); Or write your own wrapper
Things to Unlearn Avoid the old C-style algorithms, instead, use modern C++ algorithms
Things to Unlearn For example, qsort() is a C-style algorithm with following signature: Memory to be sorted Number of elements in memory Number of bytes in one element void qsort (void *base, size_t num, size_t size, int (*comparator) (const void *, const void *)); Comparison function to compare two elements // Call it as follows for a double array qsort(my. Double. Array, n, sizeof(double), compare_double);
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));
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
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
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
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
Old C++ Versus New C++ auto type deduction Old New circle* p = new circle(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 matchn"; } for (vector<circle*>: : iterator i = vw. begin(); i != vw. end(); ++i) { delete *i; not exception-safe } missing try/catch, delete p; __try/__finally T* shared_ptr<T> new make_shared 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 matchn"; } ); no need for “delete” automatic lifetime management exception-safe for/while/do std: : algorithms [&] lambda functions
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
Avoid Delete LE TE Write your code in such a way that there is never a need to use delete or delete[] DE
Avoid Delete Don’t write code as follows: void foo() { My. Object* p = new My. Object(); //. . . delete p; } � It’s not exception safe!
Avoid Delete Instead use shared_ptr or unique_ptr: void foo() { unique_ptr<My. Object> p = new My. Object(); //. . . } Or, even better, just do: void foo() { My. Object obj; //. . . }
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
Automatic Lifetime = Efficient + Exception Safe class widget { private: gadget g; public: void draw(); }; lifetime automatically tied to enclosing object no leak, exception safe void f() { widget w; /*. . . */ w. draw(); /*. . . */ } 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(); }”
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 referencecount cycles Side-note: Never use the old auto_ptr, it’s officially deprecated!
The Heap and Smart Pointersunique ownership class node { vector<unique_ptr<node>> children; node* parent; /* … */ public: node( node* parent_) : parent(parent_) { children. push_back( new node(…) ); /* … */ } }; 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
C++ and Garbage Collection “C++ is the best language for garbage collection principally because it creates less garbage. ” — Bjarne Stroustrup
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
Containers Your default container: vector compact, efficient: cachefriendly, prefetcher-friendly C-style arrays set: Like map, but only keys Avoid using Instead use modern constructs such as STL containers � std: : vector � std: : array � std: : map fixed size vector � std: : unordered_set � std: : multiset � std: : unordered_map � std: : list � std: : multimap � std: : forward_list � std: : unordered_multimap � std: : set Key-value-pairs: map (tree) or unordered_map (hash)
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";
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
Loops arbitrary length lambda Old bodies, just put the loop body inside the lambda New for/while/do std: : algorithms [&] lambda functions for (auto i = v. begin(); i != v. end(); ++i) { /*. . . */ } for_each (begin(v), end(v), [](string& s) { for_each to visit each /*. . . */ element } ); find_if to find a match auto i = v. begin(); for (; i != v. end(); ++i) { if (*i > x && *i < y) break; } auto i = find_if(begin(v), end(v), [=](int i) { return i > x && i < y; } prefer non); member begin()/end()
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
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() � find_if(): � sort(), for not-in-place semantics Your default search algorithm lower_bound(), …: Your default sorting and searching
Algorithms Utility Algorithms � min(), max(), minmax(), swap() � minmax() example (C++11) int x 1 = 2, x 2 = 9, x 3 = 3, x 4 = 12; pair<int, int> p 1 = minmax({x 1, x 2, x 3, x 4}); cout << "Minmax of 4 elements is " << p 1. first << ", " << p 1. second << endl;
Algorithms Nonmodifying algorithms � Search algorithms find(), 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 equal(), mismatch(), … � Operational algorithms for_each() algorithms
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 8 s auto 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), [](int i){return i == 1; });
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 num 1, int num 2){return num 1 * num 2; }); double geomean = pow(mult, 1. 0 / vec. size()); // Create a vector with values 5 6 7 8 9 10 11 12 13 14 vector<int> vec(10); iota(begin(vec), end(vec), 5);
Algorithms Modifying algorithms � transform(), copy(), copy_if(), move(), swap_ranges(), replace_if(), fill(), generate(), remove_if(), reverse(), rotate(), next_permutation(), …
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());
Algorithms Sorting algorithms � sort(), stable_sort(), partial_sort(), merge(), … Set algorithms � set_union(), set_intersection(), set_difference(), set_symmetric_difference(), …
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& w 1, const widget& w 2) { return w 1. weight() < w 2. weight(); } sort(begin(v), end(v), comp); auto i = lower_bound(begin(v), end(v), w, comp);
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
Move Semantics C++11 Move Semantics increases efficiency and results in cleaner, easier to understand code Why is move semantics useful?
Move Semantics – Why useful? set<widget> load_huge_data() { set<widget> ret; // … load data and populate ret … return ret; } vector<string> v = AMillion. Strings(); v. insert(begin(v)+v. size()/2, "tom"); v. insert(begin(v)+v. size()/2, "richard"); v. insert(begin(v)+v. size()/2, "harry"); efficient, no deep copyshuffle (just 1. 5 M ptr/len assignments) widgets = load_huge_data(); efficient, no deep copy no need for “heap allocation + return a pointer” workaround Huge. Matrix operator+( const Huge. Matrix&, const Huge. Matrix& ); hm 3 = hm 1+hm 2; efficient, no extra copies
Move Semantics – How To Implement? Needs: � � Move constructor Move assignment operator class my_class { unique_ptr<Big. Huge. Data> data; public: /*. . . */ my_class(my_class&& other) : data(move(other. data)) { } my_class& operator=(my_class&& other) { data = move(other. data); } check (if appropriate) }; void method() { if (!data) throw "moved-from object"; }
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
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
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<impl> pimpl; // opaque type here }; my_class. h 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) my_class. cpp { /*. . . set impl values. . . */ } Avoids rebuild cascades � Most appropriate for types used often �
Resources “Writing modern C++ code: how C++ has evolved over the years” – Herb Sutter � “Going. Native 2012, Keynote: C++ Style” – Bjarne Stroustrup � http: //channel 9. msdn. com/Events/Going. Native-2012/Keynote. Bjarne-Stroustrup-Cpp 11 -Style Presentations from Going. Native 2012 � http: //channel 9. msdn. com/Events/BUILD 2011/TOOL-835 T http: //channel 9. msdn. com/Events/Going. Native-2012 Professional C++, 2 nd Edition � http: //www. wiley. com/Wiley. CDA/Wiley. Title/product. Cd-0470932449. html
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.
- Ibm rational software architect
- Rational software architect
- Rational software architect
- Rational software architect
- Rsa uml
- Learning task 2 im an architect
- Architect act 1967
- Interface design diagram
- Leadership architect competencies
- Sarah mocke
- Risc os
- Requirements management enterprise architect
- Platform architect synopsys
- Prosessikaavion piirtäminen
- Architect's home in the ravine
- Dpm architect
- Chief network architect
- Xbrl taxonomy editor
- Akta arkitek 1967
- American architect canada
- The architect of french absolutism was
- Activity diagram in enterprise architect
- Vikram goyal architect
- Zaki yasin architect
- Piramīdas diagonālšķēlums
- John dobson architect
- Architect of the concept of number system
- Enterprise architect subversion
- Architect big ben
- The vertex form
- Stone age architect
- Schroder house architect
- Uurloon stagiair architect
- What does drawn to scale mean
- Itsc solution architect
- Keith burns architect
- Architect meaning in english
- Digital signage architect
- David olson architect
- Duty of architect
- Mark lyon architect
- Bill thomas architect
- Acquia content hub
- Webench amplifier designer
- Kenneth turner architect
- Software architecture design patterns
- Angela s. became a famous architect
- Switch light os
- The architect or “father of american public health” was
- Axtec calender
- Enterprise architect import database schema
- John crawford architect
- Dpm architect
- Aswathy mohan architect