1 / 50

Les nouveautés de C++ Ecrire du code C++ Moderne (LAN207)

Les nouveautés de C++ Ecrire du code C++ Moderne (LAN207). Christophe Pichaud Consultant Architecte Sogeti. Alain Zanchetta Consultant Architecte Microsoft. C++. Pourquoi cette session C++ ? . Beaucoup de développeurs connaissent le C++ mais n’en écrivent qu’occasionnellement

howe
Download Presentation

Les nouveautés de C++ Ecrire du code C++ Moderne (LAN207)

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. Les nouveautés de C++Ecrire du code C++ Moderne (LAN207) Christophe PichaudConsultant Architecte Sogeti • Alain ZanchettaConsultant Architecte • Microsoft

  2. C++

  3. Pourquoi cette session C++ ? • Beaucoup de développeurs connaissent le C++ mais n’en écrivent qu’occasionnellement • Utilisation tactique (Win32, COM): plus du C que du C++ • Manque de temps pour suivre les évolutions du langage • Le C++ fait peur… • Il se passe « enfin » quelque chose dans le monde C++ • Regain d’intérêt de la part des développeurs • Evolutions du langage – standard C++ 11 • Cette présentation montre le nouveau visage du C++ • Plus simple, plus sûr • Et toujours aussi performant ! • Level 400 => 200

  4. Pourquoi choisir C++ ? “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

  5. La normalisation du C++ • The C++ Standards Commitee • http://www.open-std.org/jtc1/sc22/wg21/ • 2011 : Approbation du standard C++0x • Amélioration de l’implémentation dans « VC++ 11 » • 2008: Draft pour C++0x • Implémentation (partielle) dans Visual C++ 2010 • 2005: TR1= Library Technical Report 1 • Visual C++ 2008 + TR 1 • 2003: TC1 = corrections C++98 • 1998: C++ devient un standard ISO (« C++98 »)

  6. TR1..C++0x.. C++ 11 C++ 0x lambdas r-value reference auto decltype static_assert Thread mutex future<T> vector<vector<int>> variadic templates … TR1 - Technical Report 1 shared_ptr<T> weak_ptr<T> unique_ptr<T> regex tuple array …

  7. C++, mythes et réalités • principes et techniques • gestion des erreurs • pointers • Code crado mais je continue sur le même modèle… • Un langage orienté objet compliqué ! • cast • Orienté  objet • Compliqué à apprendre ! • Des macros et de goto ! • Peu productif ! • Structure de données compactes et efficaces • Bas niveau ! • Interfaces riches • Template meta-programming • Non sécurisée, dangereux ! • C’est du C ! • Code dur à maintenir • new / delete • Un bon code • le style C++ 11

  8. C++ refreshed

  9. Illustration • Soitun point A • Soit un ensemble de polygones • Trouver le premier polygone qui contient A • NB: ce n’est pas un problème de mathématiques mais une petite illustration de l’évolution du C++ 

  10. C++ « classique » C# CPolygon *Search(int x, int y) { CPoint pt(x,y); vector<CPolygon*> polys; ReadPolys(polys); CPolygon *ret = NULL; for (vector<CPolygon*>::iterator beg = polys.begin(); beg!=polys.end();++beg) { if ((*beg)->Contains(pt)) { ret = *beg; break; } } for (vector<CPolygon*>::iterator beg = polys.begin(); beg!=polys.end();++beg) if ((*beg) && (*bet != ret)) delete *beg; return ret; } PolygonSearch(int x, int y) { Point pt = new Point(x,y); List<Polygon> polys = ReadPolys(); return polys.FirstOrDefault( p => p.Contains(pt)); }

  11. Gestion de la mémoire • Plus grosse « difficulté du C++ » : la gestion de mémoire • difficile d’éviter les fuites, les doubles libérations, l’utilisation de zones déjà libérées • Il n’y a pas de manière unique d’allouer la mémoire en C++ • Mais il y a un mécanisme de libération déterministe : Cycle de vie aussuré par le scope, avec création du membre gadget w.g. Gestion automatique du cyle de vie lié à l’objet contenant void f() { widget w; ::: w.draw(); ::: } class widget { private: gadget g; public: void draw();}; Destruction automatique et de-allocation de w et w.g

  12. Libérationdéterministe • Principe • RAII = Resource Acquisition Is Initialisation • Applicable à toutes les ressources « précieuses : • Mémoire • fichiers, sockets, handles Windows • Destruction déterministe (i.e. pas besoin de « using ») • “C++ is the best language for garbage collection principally because it creates less garbage.”Bjarne Stroustrup

  13. Caractéristiquesde shared_ptr<T> • Un template C++ disponibledans<memory> shared_ptr<Polygon> sp(new Polygon()); sp->Draw(…); return sp; • Basésur le comptage de références • Gain de productivité & robustesseimportants avec impact minimal sur les perfs • Compatible avec les conteneurs STL • Compatible avec le polymorphisme : • shared_ptr<Derived>est convertible en shared_ptr<Base> • Ne casse pas le mécanisme de comptage des références • Libérationparticulière : shared_ptr<int> sp((int*)CoTaskMemAlloc(sizeof(int)),CoTaskMemFree);

  14. shared_ptr est Non-Intrusif • Possibilitéd’instanciershared_ptr<T> sans modifier T • La gestion des références (uses/weaks) estdans le shared_ptr • Fonctionne avec les types prédéfinis: shared_ptr<int> • S’incorporedans le code sans modifier les types existants • Un même type peutêtremanipuléparfois via un shared_ptr et d’autresfois via d’autresmécanismes

  15. make_shared<T>() • VS 2008 SP1 (VC9 SP1): shared_ptr<T> sp(new T(args)); shared_ptr<T> sp(new T(args), del, alloc); • VS 2010 (VC10): shared_ptr<T> sp = make_shared<T>(args); voireauto sp = make_shared<T>(args); shared_ptr<T>sp = allocate_shared<T>(alloc, args); voireauto sp = allocate_shared<T>(alloc, args); • Simple et élegant • Écrire le type Tuneseulefois • Performant • Uneseuleallocation pour l’objet et le bloc de comptage

  16. Casser les cycles avec weak_ptr<T> • Patterns : parent / enfants, observer • Solution : weak_ptr<T>, lock(), expired() • lock : transformation en shared_ptr • expired : tester si la ressource est disponible staticvoiddo_lock (const char *title, weak_ptr<resource> wp) { shared_ptr<resource> sp = wp.lock(); show(title, sp); } int main() { // demonstratememberfunctionlock shared_ptr<resource> sp0(new resource); weak_ptr<resource> wp0(sp0); do_lock("weak_ptrwithresource", wp0); sp0.reset(); do_lock("expiredweak_ptr", wp0); return 0; } int main() { // demonstrate member function expired cout << boolalpha; shared_ptr<resource> sp(new resource); weak_ptr<resource> wp(sp); cout << "points to resource: " << wp.expired () << '\n'; sp.reset (); cout << "expired: " << wp.expired() << '\n'; return 0; }

  17. unique_ptr<T> • Uneseuleréférence de l’objet unique_ptr<Cat> c(new Cat); unique_ptr<Cat> c2(Cat::Load(…)); • Remplaceauto_ptr, qui estobsolète • Compatible avec les collections STL (containers) • Non copiablemaisdéplaçable unique_ptr<Cat> c(new Cat); unique_ptr<Dog> d; d.reset(new Dog); unique_ptr<Monster> m_src(new Monster); unique_ptr<Monster> m_dest(move(m_src));

  18. Paroles d’experts ! • Effective C++, Third Edition (2005) by Scott Meyers: • "shared_ptr may be the most widely useful component in TR1." • C++ Coding Standards (2005) by Herb Sutter and Andrei Alexandrescu: • "Store only values and smart pointers in containers. To this we add: If you use [Boost] and [C++TR104] for nothing else, use them for shared_ptr."

  19. delete

  20. shared_ptr<CPolygon> Search(int x, int y) { CPoint pt(x,y); vector<shared_ptr<CPolygon>> polys; ReadPolys(polys); for (vector<shared_ptr<CPolygon>>:: iteratorbeg = polys.begin(); beg!=polys.end();++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr; } C++ C# CPolygon *Search(int x, int y) { CPoint pt(x,y); vector<CPolygon*> polys; ReadPolys(polys); CPolygon *ret = NULL; for (vector<CPolygon*>::iterator beg = polys.begin(); beg!=polys.end();++beg) { if ((*beg)->Contains(pt)) { ret = *beg; break; } } for (vector<CPolygon*>::iterator beg = polys.begin(); beg!=polys.end();++beg) if ((*beg) && (*bet != ret)) delete *beg; return ret; } PolygonSearch(int x, int y) { Point pt = new Point(x,y); List<Polygon> polys = ReadPolys(); return polys.FirstOrDefault( p => p.Contains(pt)); }

  21. nullptr • nullptrexprime un pointeurnul • Cen’est pas un int class Foo { public: Foo(const char *s); Foo(int n); } … Foo f(NULL); Foo f(nullptr);

  22. NULL

  23. auto • Avant… • vector<shared_ptr<CPolygon>>::iteratorbeg = polys.begin(); • long et fastidieux à écrire ! • Maintenant, avec « auto » • auto beg = polys.begin(); • Type déduit par le compilateur • Equivalent de « var » en C#

  24. auto: pourquoi l’utiliser ? • autoutilise les règles de détectiond’arguments des templates • const auto * p = foo et const auto& r = barcompilent • auto... • Réduit la taille du code et en améliore la lisibilité • Permetd’éviter les erreurs de types, troncations, … • Fonctionnetrèsbien avec les types comme les lambdas

  25. shared_ptr<CPolygon> Search(int x, int y) { CPoint pt(x,y); vector<shared_ptr<CPolygon>> polys; ReadPolys(polys); for (auto beg = polys.begin(); beg != polys.end(); ++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr; } C++ C# shared_ptr<CPolygon> Search(int x, int y) { CPoint pt(x,y); vector<shared_ptr<CPolygon>> polys; ReadPolys(polys); for (vector<shared_ptr<CPolygon>>:: iteratorbeg = polys.begin(); beg!=polys.end(); ++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr; } PolygonSearch(int x, int y) { Point pt = new Point(x,y); List<Polygon> polys = ReadPolys(); return polys.FirstOrDefault( p => p.Contains(pt)); }

  26. Move Semantics, Perfect Forwarding • RValue = tout ce qui n’est pas LValue • Les références de Rvaluepermettentdeux choses importantes : • Déplacement (move semantics) : pour la performance • Perfect forwarding: pour la généricité • = uneseulefonctiongénérique qui accepte des arguments quelconques et les transmet de manièretransparente à uneautrefonction en préservantleur nature (const, lvalue, rvalue, etc) • Ex : make_shared • Les patterns de déplacement et de perfect forwarding sont simples à mettre en oeuvre • Maisilss’appuientsur de nouvellesrèglesd’initialisation, de résolution de surcharge, de déduction des paramètres des templates, etc. • Les conteneurs STL sont “move aware”

  27. Mécanique du Move / Value Types class my_class {BigHugeData *data; public: my_class(constmy_class& src) { … }my_class(my_class&& other) { data = other.data; other.data = nullptr; } … }; my_class f() { my_classtmp; … return tmp; } void main() { my_class c = f(); } Appel du Move Constructor

  28. shared_ptr<CPolygon> Search(int x, int y) { CPoint pt(x,y); auto polys = ReadPolys(polys); for (auto beg = polys.begin(); beg != polys.end(); ++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr; } C++ C# shared_ptr<CPolygon> Search(int x, int y) { CPoint pt(x,y); vector<shared_ptr<CPolygon>> polys; ReadPolys(polys); for (auto beg = polys.begin(); beg != polys.end(); ++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr; } PolygonSearch(int x, int y) { Point pt = new Point(x,y); List<Polygon> polys = ReadPolys(); return polys.FirstOrDefault( p => p.Contains(pt)); }

  29. Uneclasse C++11 type • uneclassepossède par défaut5 opérations • Un constructeur par copie • Un opérateur de copie • Un constructeur de move • Un opérateur de move • Un destructeur • Attention aux implémentations par défaut

  30. =default et =delete • Indiquerexplicitement un opérateur de copie par défault class Y { // ... Y& operator=(const Y&) = default; // default copysemantics Y(const Y&) = default; } • Indiquerl’interdiction de la copie class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; };

  31. 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”; Conteneurs STL dictionary: map (arbre) ou unordered_map (hash) vector<string> v;v.push_back( “Geddy Lee” ); array<string,50> a; container par défaut: vector compact, efficace, cache, préfetch vecteur de taillle fixe: array compact, efficace, cache, préfetch

  32. cbegin(), cend(), crbegin(), crend() vector<int> v; for (auto i = v.begin(); i != v.end(); ++i) { // i is vector<int>::iterator } for (auto i = v.crbegin(); i != v.crend(); ++i) { // i is vector<int>::const_iterator } // Formepréférée : begin() et end() for (auto i = begin(v); i != end(v); ++i) { … }

  33. Algorithmes : trois catégories • Parcours simples • Exemple : for_each = le plus simple • Parcours avec transformations • Exemple : copy = copie tous les éléments répondant à une condition • Tris • Exemples : sort, stable_sort, lower_bound

  34. Parcours simples • All of • Any of • None of • For each • Find • Find end • Find first • Adjacent Find • Count • Mismatch • Equal • Is permutation • Search

  35. Exemple : Find first template<class InputIterator, class Predicate> InputIteratorfind_if(InputIterator first,InputIteratorlast, Predicatepred); • Retourne le premier élémentvérifiant le prédicat • Predicate : • Fonctions • Classesurchargeant operator() • Lambda

  36. Transformations • Copy • Move • Swap • Transform • Replace • Fill • Generate • Remove • Unique • Reverse • Rotate • Randomshuffle • Partitions

  37. Exemple Transform template<class InputIterator, class OutputIterator, class UnaryOperation> OutputIteratortransform(InputIteratorfirst,InputIteratorlast, OutputIteratorresult, UnaryOperationop); • Exemple: impression de tous les éléments d’un conteneur : copy(points.begin(), points.end(), ostream_iterator<CPoint>(cout, "\n" ));

  38. Tri et assimilés • Sort • Stable_sort • Partial_sort • Nthelement • Binarysearch : lower_bound, upper_bound • Merge

  39. Exemple : sort template<class RandomAccessIterator, class Compare> void sort(RandomAccessIterator first, RandomAccessIteratorlast, Compare comp); • Trie les éléments selon « comp » • Comp = ordre strict (< ou > et non £ ou ³) boolPlusHaut(CPoint &pt1, CPoint &pt2) { return pt1.Y() > pt2.Y(); } sort(points.begin(), points.end(), PlusHaut);

  40. Fonctions et prédicats Function for_each(InputIterator first, InputIterator last, Function f); InputIteratorfind_if(InputIterator first, InputIteratorlast, Predicate pred); void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp); Fonctions simples : boolPlusHaut(CPoint &pt1,CPoint &pt2) { return pt1.Y() > pt2.Y(); } Classes surchargeant () : class DistancePoint { protected: constCPoint &_ptr; public: DistancePoint(constCPoint &ptr) : _ptr(ptr) {} booloperator()(CPoint &pt1, CPoint&pt2) { return_ptr.Distance2(pt1) < _ptr.Distance2(pt2); } }; Et lambdas !

  41. Le B.A. BA des lambdas • Les Lambda Expressions définissent et construisent des classes fonctions anonymes • La Lamba Expression for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); Est équivalente à structLambdaFunctor { void operator()(int n) const { cout << n << " "; } }; … for_each(v.begin(), v.end(), LambdaFunctor);

  42. Compléments • Une lambda peut contenir plusieurs instructions • voidpar défaut, -> type pour préciser le type de retour • [] sert à indiquer ce qu’on doit capturer du contexte • Utilisation de variables extérieures à la lambda v.erase(remove_if(v.begin(), v.end(), [x, y](int n) { return x < n && n < y; }), v.end()); • Lambda Stateless: [] • Les copies capturées « survivent » à leur contexte • Possibilité de capture par référence • Capture de toutes les variables [=] ou [&]

  43. shared_ptr<CPolygon> Search(int x, int y) { CPoint pt(x,y); auto polys = ReadPolys(); auto found = find_if(begin(polys), end(polys), [pt](shared_ptr<CPolygon> pol) { return pol->Contains(pt); }); return (found != polys.end()) ? *found : nullptr; } C++ C# shared_ptr<CPolygon> Search(int x, int y) { CPoint pt(x,y); auto polys = ReadPolys(polys); for (auto beg = polys.begin(); beg != polys.end(); ++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr; } PolygonSearch(int x, int y) { Point pt = new Point(x,y); List<Polygon> polys = ReadPolys(); return polys.FirstOrDefault( p => p.Contains(pt)); }

  44. shared_ptr<CPolygon> Search(int x, int y) { CPoint pt(x,y); auto polys = ReadPolys(); auto found = find_if(begin(polys), end(polys), [pt](shared_ptr<CPolygon> pol) { return pol->Contains(pt); }); return (found != polys.end()) ? *found : nullptr; } C++ 98 C++ 2011 CPolygon *Search(int x, int y) { CPoint pt(x,y); vector<CPolygon*> polys; ReadPolys(polys); CPolygon *ret = NULL; for (vector<CPolygon*>::iterator beg = polys.begin(); beg!=polys.end();++beg) { if ((*beg)->Contains(pt)) { ret = *beg; } } for (vector<CPolygon*>::iterator beg = polys.begin(); beg!=polys.end();++beg) if ((*beg) && (*bet != ret)) delete *beg; return ret; }

  45. Initialisation des listes • Maintenant, on peutécrirecela vector<double> v ={ 1, 2, 3.456, 99.99 }; list<pair<string,string>> languages ={ {"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"} }; map<vector<string>,vector<int>> years ={ { {"Maurice","Vincent", "Wilkes"},{1913, 1945, 1951, 1967, 2000} }, { {"Martin", "Ritchards"} {1982, 2003, 2007} }, { {"David", "John", "Wheeler"}, {1927, 1947, 1951, 2004} } }; • L’utilisation de {}est possible via unefonction (souvent par un constructeur) qui accepte un argument std::initializer_list<T> vector (std::initializer_list<E> s) // initializer-list constructor

  46. VC++ & C++11 Techdays 2012 VC10RTM VC11RTM OOBRTM VC11DP VC11Beta OOBCTP Apr 2010 + lambdas, move/&&,auto, decltype,auto fndecls,extern template,nullptr, … Sep2011 + completeC++11 stdlib: thread/mutex,async, future, … + track changes(lambdas, &&, …) Feb2012 + C++11range-for,final,override Out-Of-BandReleases + progressively roll out C++11 initializer lists,template aliases, variadic templates, constexpr, noexcept, =default/delete, … Survey: bit.ly/mscpp11

  47. A retenir • Systématiser l’usage des Smart Pointers = plus de delete • shared_ptr, weak_ptr, unique_ptr, auto_ptr • make_shared • Oublier NULL et utiliser null_ptr • Capitaliser sur les conteneurs et algorithmes de la STL • Intégrer le déplacement dans les membres spéciaux

  48. Pour aller plus loin • Le standard C++ • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3337.pdf • Channel 9 : GoingDeep (STL, TR1, etc) • http://channel9.msdn.com/Shows/Going+Deep • Channel 9 : Going Native • http://channel9.msdn.com/Events/GoingNative/GoingNative-2012 • C++ Sessions de la Build 2011 • http://channel9.msdn.com/Events/BUILD/BUILD2011?sort=status&direction=asc&t%5B0%5D=c%2B%2B#tab_sortBy_status • What's New for Visual C++ in Visual Studio 11 Developer Preview • http://msdn.microsoft.com/en-us/library/hh409293(v=vs.110).aspx • Blog équipe VC++ • http://blogs.msdn.com/b/vcblog/

  49. Pour aller plus loin • Chaque semaine, les DevCampsALM, Azure, Windows Phone, HTML5, OpenDatahttp://msdn.microsoft.com/fr-fr/devcamp • Téléchargement, ressources et toolkits : RdV sur MSDNhttp://msdn.microsoft.com/fr-fr/ • Les offres à connaître 90 jours d’essai gratuit de Windows Azure www.windowsazure.frJusqu’à 35% de réduction sur Visual Studio Pro, avec l’abonnement MSDN www.visualstudio.fr Prochaines sessions des Dev Camps

More Related