Effective Code Transformations in C++

3,784 views

Published on

Slide del talk presentato il 30 Novembre 2013 all'Italian Agile Day a Reggio Emilia (Marco Arena & Paolo Polce)

Published in: Technology, Sports
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,784
On SlideShare
0
From Embeds
0
Number of Embeds
2,784
Actions
Shares
0
Downloads
23
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Effective Code Transformations in C++

  1. 1. Effective Code Transformations in C++ Marco Arena Paolo Polce marco@italiancpp.org paolo@webshell.it Reggio Emilia, 30 Novembre 2013
  2. 2. Italian C++ Community www.italiancpp.org @italiancpp 2
  3. 3. Ancora evolvono il C++??! 3
  4. 4. When I hear they’re adding features to C++ This PLT Life - http://this-plt-life.tumblr.com/ 4
  5. 5. Outline • C++11, benvenuto nel team! – C++98  C++11 & snippet C# • Il team cambia stile & coding standards – Design patterns – Multi-threaded C++ • Alcune linee guida 5
  6. 6. Outline • C++11, benvenuto nel team! – C++98  C++11 & snippet C# • Il team cambia stile & coding standards – Design patterns – Multi-threaded C++ • Alcune linee guida 6
  7. 7. C++ o C#?! var dati = new List<int>(){1,2,3,4,5}; 7
  8. 8. C++ o C#?! var dati = new List<int>(){1,2,3,4,5}; auto dati = vector<int>{1,2,3,4,5}; 8
  9. 9. auto // C++98 vector<int> vec (10); vector<int>::iterator it = vec.begin();
  10. 10. auto // C++98 vector<int> vec (10); vector<int>::iterator it = vec.begin(); it 10 1 2 3 4 12 6 it 5 7 11 13 10
  11. 11. auto // C++98 vector<int> vec (10); vector<int>::iterator it = vec.begin(); // C++11 vector<int> vec (10); auto it = vec.begin();
  12. 12. auto // C++98 vector< pair<string, int> > cards = ... ; vector< pair<string, int> >::iterator it = cards.begin(); 12
  13. 13. auto // C++98 vector< pair<string, int> > cards = ... ; vector< pair<string, int> >::iterator it = cards.begin(); // C++11 auto it = cards.begin(); 13
  14. 14. range-based iteration // C++98 for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { cout << *it << " "; } 14
  15. 15. range-based iteration // C++11 for (auto i : vec) { cout << i << " "; } 15
  16. 16. range-based iteration // C++11 for (auto i : vec) { cout << i << " "; } for (const auto& i : vec) { cout << i << " "; } 16
  17. 17. range-based iteration C++98 C++11 for ( vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { cout << *it << " "; } for (auto i : vec) { cout << i << " "; } C# foreach (var i in arrayList) { System.Console.Write(i); } 17
  18. 18. lambdas & algorithms // C++98 vector<int>::const_iterator find_in_range(const vector<int>& vec) { vector<int>::const_iterator i = vec.begin(); for( ; i != vec.end(); ++i ) { if( *i > 0 && *i < 10 ) break; } return i; } 18
  19. 19. lambdas & algorithms // C++98 bool elem_in_range(int elem) { return elem > 0 && elem < 10; } vector<int>::const_iterator it = find_if (vec.begin(), vec.end(), elem_in_range); 19
  20. 20. lambdas & algorithms // C++11 auto it = find_if (begin(vec), end(vec), [](int i) { return i > 0 && i < 10; }); 20
  21. 21. lambdas & algorithms // C++14 auto it = find_if (begin(vec), end(vec), [](auto i) { return i > 0 && i < 10; }); 21
  22. 22. lambdas & algorithms C++14 [](auto i) { return i > 0 && i < 10; } C# (int i) => i > 0 && i < 10; 22
  23. 23. C++ o C#?! var dati = new List<int>(){1,2,3,4,5}; auto dati = vector<int>{1,2,3,4,5}; 23
  24. 24. initializer lists // C++98 int arr[] = {1,2,3,4,5}; vector<int> data; data.push_back(1); data.push_back(2); ... vector<int> data (arr, arr + 5); 24
  25. 25. initializer lists // C++98 int arr[] = {1,2,3,4,5}; vector<int> data (arr, arr + 5); // C++11 vector<int> data = {1,2,3,4,5}; // oppure (auto-everything syntax): auto data = vector<int>{1,2,3,4,5}; 25
  26. 26. initializer lists C++98 C++11 vector<int> data; data.push_back(1); data.push_back(2); data.push_back(3); ... auto data = vector<int>{1,2,3,4,5}; C# var dati = new List<int>() {1, 2, 3, 4, 5}; 26
  27. 27. smart pointers // C++98 { Car* car = new Car(...); ... car->Move(); ... delete car; } 27
  28. 28. smart pointers // C++98 { Car* car = new Car(...); ... car->Move(); throw exception(…) ... delete car; } 28
  29. 29. smart pointers // C++98 Car *car = NULL; try { car = new Car(...); car->Move(); delete car; } catch(...) { delete car; ASSERT(FALSE); LOG(ERROR) << "critical"; throw; } 29
  30. 30. smart pointers // C++98 catch(...) { delete car; ASSERT(FALSE); LOG(ERROR) << "critical"; throw; } 30
  31. 31. smart pointers { // C++11 unique_ptr<Car> car {new Car{arg1}}; ... car->Move(); ... } // delete automatico // C++14 auto car = make_unique<Car>(arg1) 31
  32. 32. Outline • C++11, benvenuto nel team! – C++98  C++11 & snippet C# • Il team cambia stile & coding standards – Design patterns – Multi-threaded C++ • Alcune linee guida 32
  33. 33. Modern C++: Factory // C++98 IWriter* Create(...) { ... return new CoutWriter(...); } // chiamante: IWriter* writer = Create (...); ... delete writer; 33
  34. 34. Modern C++: Factory // C++11 unique_ptr<IWriter> Create (...) { ... return unique_ptr<IWriter>(new CoutWriter(...)); } // chiamante: auto writer = Create(...); 34
  35. 35. Modern C++: Factory // C++98 class WriterFactory { public: IWriter* Create(const string& where) { if (where == "cout") return new CoutWriter(); if (where == "dbgview") return new DbgViewWriter(); if (where == " null") return new NullWriter(); throw exception("where to write?"); } }; 35
  36. 36. Modern C++: Factory // C++11-14 class WriterFactory { public: unique_ptr<IWriter> Create(const string& where) { static map<string, function<unique_ptr<IWriter>()>> m = { {"cout", []{return make_unique<CoutWriter>()}}, {"dbgview", []{return make_unique<DbgViewWriter>()}}, {"null", []{return make_unique<NullWriter>()}} }; return m.at(where)(); // può sollevare eccezione // oppure una policy diversa } 36 };
  37. 37. Modern C++: RAII & DEFER bool FileExists(const char* path) { ifstream file{path}; // file.open() return file.is_open(); } // file.close() automatico 37
  38. 38. Modern C++: RAII & DEFER void SomeFuntion() { ... Anything ... Log("SomeFunction executed"); } 38
  39. 39. Modern C++: RAII & DEFER void SomeFuntion() { ... Anything ... throw exception(…) Log("SomeFunction executed"); } 39
  40. 40. Modern C++: RAII & DEFER // go style func SomeFuntion() { defer func() { Log("SomeFunction executed") } ... Anything ... } 40
  41. 41. Modern C++: RAII & DEFER void SomeFuntion() { defer d{ []{ Log("SomeFunction executed"); }}; ... Anything ... } 41
  42. 42. Modern C++: RAII & DEFER class defer { function<void()> m_toExec; public: defer(function<void()> f) : m_toExec{f} { } ~defer() { m_toExec(); } }; Qui una versione migliore e completa: http://www.italiancpp.org/2013/07/16/defer-con-raii-lambda/ 42
  43. 43. Modern C++: RAII & DEFER Live Demo git clone https://ilpropheta@bitbucket.org/ilpropheta/iad2013.git main.cpp: DeferTest 43
  44. 44. Outline • C++11, benvenuto nel team! – C++98  C++11 & snippet C# • Il team cambia stile & coding standards – Design patterns – Multi-threaded C++ • Alcune linee guida 44
  45. 45. Multi-Threaded C++ int main() { vector<int> vec(100000); iota(begin(vec), end(vec), 0); // 0 1 2 3 4 ... int avg = 0; thread t1 { [&]{ avg = accumulate(begin(vec), end(vec), 0)/vec.size(); }}; auto maxEl = max_element(begin(vec), end(vec)); t1.join(); cout << "max: " << *maxEl << endl; cout << "avg: " << avg << endl; } 45
  46. 46. Multi-Threaded C++ Live Demo git clone https://ilpropheta@bitbucket.org/ilpropheta/iad2013.git main.cpp: ThreadTest 46
  47. 47. Multi-Threaded C++ int main() { vector<int> vec(100000); iota(begin(vec), end(vec), 0); auto willbeAvg = async ( [&]{ return accumulate(begin(vec), end(vec), 0)/vec.size(); }}; cout << "max: " << *max_element(begin(vec), end(vec)) << endl; cout << "avg: " << willbeAvg.get() << endl; } 47
  48. 48. Multi-Threaded C++ Live Demo git clone https://ilpropheta@bitbucket.org/ilpropheta/iad2013.git main.cpp: FutureTest 48
  49. 49. Multi-Threaded C++ future promise get() v set_value(v) Thread 1 Thread 2 49
  50. 50. Multi-Threaded C++ Live Demo git clone https://ilpropheta@bitbucket.org/ilpropheta/iad2013.git main.cpp: PromiseTest 50
  51. 51. Multi-Threaded C++: PPL void vector_mult(vector<double>& v, double c) { for_each( begin(v), end(v), [&](double& n) { n *= c; } ); } 51
  52. 52. Multi-Threaded C++: PPL #include <ppl.h> using namespace Concurrency; void vector_mult(vector<double>& v, double c) { parallel_for_each( begin(v), end(v), [&](double& n) { n *= c; } ); } 52
  53. 53. Multi-Threaded C++: PPL Live Demo git clone https://ilpropheta@bitbucket.org/ilpropheta/iad2013.git PPLSesame.cpp 53
  54. 54. Outline • C++11, benvenuto nel team! – C++98  C++11 & snippet C# • Il team cambia stile & coding standards – Design patterns – Multi-threaded C++ • Alcune linee guida 54
  55. 55. Alcune linee guida • Devo migrare tutto subito? – No, intanto assicurati di cosa supporta il tuo compilatore. – Inizia migrando le cose deprecate (e.g. auto_ptr). – Aggiungi qualche test su quello che stai modificando. – Vale sempre il principio del boyscout… 55
  56. 56. Alcune linee guida • Il mio compilatore non supporta alcune feature del C++11. Che devo fare? – Se puoi, pianifica una migrazione del compilatore. – Individua cosa potrà beneficiare del C++11 e come lo riscriveresti. – Metti dei reminder per quando migrerai, tipo: //TO-DO-CPP11: … 56
  57. 57. Alcune linee guida • Il miglior consiglio per usare C++11/C++14? – Provalo! – Il materiale di qualità sul C++ è aumentato. – Frequenta isocpp.org – Frequenta italiancpp.org  57
  58. 58. Marco & Paolo Marco Arena marco@italiancpp.org http://marcoarena.wordpress.com Paolo Polce paolo@webshell.it @paolopolce webshell.it agileworks.it 58
  59. 59. ~talk() noexcept { answer_questions(); } 59
  60. 60. ~talk() noexcept { answer_questions(); } Quanto è nerd questa slide? 60
  61. 61. Grazie! 61
  62. 62. Bonus: non-member begin/end // C++98 vector<int>::iterator it = vec.begin(); int arr[] = {1,2,3,4,5}; arr.begin(); // eh ??? // C++11 auto it = begin(vec); auto it = begin(arr); // ok! 62
  63. 63. Bonus: make_unique (1) // C++14 auto car = make_unique<Car>(arg1) • auto-everything syntax • Exception-safety: void func(unique_ptr<Car> c1, unique_ptr<Car> c2); func(unique_ptr<Car>{new Car{}}, unique_ptr<Car>{new Car{}}); • Le istruzioni per creare i due Car* possono essere riordinate dal compilatore. 63
  64. 64. Bonus: make_unique (2) func(unique_ptr<Car>{new Car{}}, unique_ptr<Car>{new Car{}}); Esempio di possibile esecuzione: 1. Allocazione memoria per la prima Car 2. Allocazione memoria per la seconda Car 3. Costruzione prima Car 4. Costruzione seconda Car 5. Costruzione primo unique_ptr 6. Costruzione secondo unique_ptr Che succede se 4 tira un’eccezione? Memory leak della prima Car! Se chiamiamo due funzioni (come make_unique), il compilatore è costretto a fare 1,2,5 insieme e poi 3,4,6! Più dettagli a questo link (Sutter) 64

×