500 likes | 609 Views
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
E N D
Les nouveautés de C++Ecrire du code C++ Moderne (LAN207) Christophe PichaudConsultant Architecte Sogeti • Alain ZanchettaConsultant Architecte • Microsoft
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
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
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 »)
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 …
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
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++
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)); }
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
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
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);
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
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
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; }
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));
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."
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)); }
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);
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#
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
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)); }
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”
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
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)); }
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
=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; };
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
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) { … }
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
Parcours simples • All of • Any of • None of • For each • Find • Find end • Find first • Adjacent Find • Count • Mismatch • Equal • Is permutation • Search
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
Transformations • Copy • Move • Swap • Transform • Replace • Fill • Generate • Remove • Unique • Reverse • Rotate • Randomshuffle • Partitions
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" ));
Tri et assimilés • Sort • Stable_sort • Partial_sort • Nthelement • Binarysearch : lower_bound, upper_bound • Merge
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);
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 !
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);
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 [&]
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)); }
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; }
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
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
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
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/
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