Les nouveautés de C++ Ecrire du code C++ Moderne (LAN207)
description
Transcript of Les nouveautés de C++ Ecrire du code C++ Moderne (LAN207)
palais des congrès Paris
7, 8 et 9 février 2012
Christophe PichaudConsultant Architecte Sogeti
Les nouveautés de C++Ecrire du code C++ Moderne (LAN207) Alain Zanchetta
Consultant ArchitecteMicrosoft
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 cette session C++ ?
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
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 »)
La normalisation du C++
TR1.. C++0x.. C++ 11TR1 - Technical Report 1shared_ptr<T>
weak_ptr<T>
unique_ptr<T>
regex
tuple
array
…
C++ 0xlambdas
r-value reference
auto
decltype
static_assert
Thread
mutex
future<T>
vector<vector<int>>
variadic templates
…
C++, mythes et réalités
Template meta-programming
Des macros et de goto !
C’est du C !
Un langage orienté objet compliqué !
Bas niveau !
Non sécurisée, dangereux !
Code dur à maintenir
Code crado mais je continue sur le même modèle…
Compliqué à apprendre !
Peu productif !
cast
new / delete
pointers
Orienté objet
Un bon code
principes et techniques
Interfaces richesStructure de données
compactes et efficaces
le style C++ 11
gestion des erreurs
C++ refreshed
Soit un point ASoit un ensemble de polygones Trouver le premier polygone qui contient ANB: ce n’est pas un problème de mathématiques mais une petite illustration de l’évolution du C++
Illustration
C++ « classique » C#
11
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;}
Polygon Search(int x, int y){ Point pt = new Point(x,y); List<Polygon> polys = ReadPolys(); return polys.FirstOrDefault( p => p.Contains(pt));}
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 :
Gestion de la mémoire
Gestion automatique du cyle de vie lié à l’objet contenant
Cycle de vie aussuré par le scope, avec création du membre gadget w.g.
Destruction automatique et de-
allocation de w et w.g
class widget {private: gadget g;public: void draw();};
void f() { widget w; ::: w.draw(); :::}
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 »)
Libération déterministe
“C++ is the best language for garbage collection principally because it creates less garbage.”
Bjarne Stroustrup
Un template C++ disponible dans <memory>shared_ptr<Polygon> sp(new Polygon());sp->Draw(…);return sp;
Basé sur le comptage de référencesGain de productivité & robustesse importants avec impact minimal sur les perfsCompatible avec les conteneurs STLCompatible 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ération particulière :shared_ptr<int> sp((int*)CoTaskMemAlloc(sizeof(int)), CoTaskMemFree);
Caractéristiques de shared_ptr<T>
Possibilité d’instancier shared_ptr<T> sans modifier TLa gestion des références (uses/weaks) est dans le shared_ptrFonctionne avec les types prédéfinis: shared_ptr<int>S’incorpore dans le code sans modifier les types existantsUn même type peut être manipulé parfois via un shared_ptr et d’autres fois via d’autres mécanismes
shared_ptr est Non-Intrusif
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);voire auto sp = make_shared<T>(args);
shared_ptr<T> sp = allocate_shared<T>(alloc, args);voire auto sp = allocate_shared<T>(alloc, args);
Simple et élegant Écrire le type T une seule fois
Performant Une seule allocation pour l’objet et le bloc de comptage
make_shared<T>()
Patterns : parent / enfants, observerSolution : weak_ptr<T>, lock(), expired() lock : transformation en shared_ptr expired : tester si la ressource est disponible
Casser les cycles avec weak_ptr<T>
static void do_lock (const char *title, weak_ptr<resource> wp){
shared_ptr<resource> sp = wp.lock();show(title, sp);
}
int main(){
// demonstrate member function lockshared_ptr<resource> sp0(new resource);weak_ptr<resource> wp0(sp0);do_lock("weak_ptr with resource", wp0);sp0.reset();do_lock("expired weak_ptr", wp0);return 0;
}
int main(){
// demonstrate member function expiredcout << 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;
}
Une seule référence de l’objetunique_ptr<Cat> c(new Cat);unique_ptr<Cat> c2(Cat::Load(…));
Remplace auto_ptr, qui est obsolèteCompatible avec les collections STL (containers) Non copiable mais dé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));
unique_ptr<T>
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."
Paroles d’experts !
delete
C++ C#
22
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;}
Polygon Search(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); vector<shared_ptr<CPolygon>> polys; ReadPolys(polys); for (vector<shared_ptr<CPolygon>>:: iterator beg = polys.begin(); beg!=polys.end();++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr;}
nullptr exprime un pointeur nulCe n’est pas un int
class Foo {public: Foo(const char *s); Foo(int n);}…Foo f(NULL);Foo f(nullptr);
nullptr
NULL
Avant… vector<shared_ptr<CPolygon>>::iterator beg =
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
auto utilise les règles de détection d’arguments des templates
const auto * p = foo et const auto& r = bar compilentauto... Réduit la taille du code et en améliore la lisibilité Permet d’éviter les erreurs de types, troncations, … Fonctionne très bien avec les types comme les lambdas
auto: pourquoi l’utiliser ?
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>>:: iterator beg = polys.begin(); beg!=polys.end(); ++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr;}
Polygon Search(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); vector<shared_ptr<CPolygon>> polys; ReadPolys(polys);
for (auto beg = polys.begin(); beg != polys.end(); ++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr;}
RValue = tout ce qui n’est pas LValueLes références de Rvalue permettent deux choses importantes :
Déplacement (move semantics) : pour la performance Perfect forwarding: pour la généricité
= une seule fonction générique qui accepte des arguments quelconques et les transmet de manière transparente à une autre fonction en préservant leur nature (const, lvalue, rvalue, etc)
Ex : make_sharedLes patterns de déplacement et de perfect forwarding sont simples à mettre en oeuvreMais ils s’appuient sur de nouvelles règles d’initialisation, de résolution de surcharge, de déduction des paramètres des templates, etc.Les conteneurs STL sont “move aware”
Move Semantics, Perfect Forwarding
class my_class { BigHugeData *data;public: my_class(const my_class& src) { … } my_class(my_class&& other) { data = other.data; other.data = nullptr; } …};
Mécanique du Move / Value Typesmy_class f(){ my_class tmp; … return tmp;}
void main(){ my_class c = f();}
Appel du Move Constructor
C++ C#
32
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;}
Polygon Search(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(polys);
for (auto beg = polys.begin(); beg != polys.end(); ++beg) { if ((*beg)->Contains(pt)) return *beg; } return nullptr;}
une classe possède par défaut 5 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
Une classe C++11 type
Indiquer explicitement un opérateur de copie par défaultclass Y { // ... Y& operator=(const Y&) = default; // default copy semantics Y(const Y&) = default; }
Indiquer l’interdiction de la copieclass X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; };
=default et =delete
vector<string> v;v.push_back( “Geddy Lee” );
array<string,50> a;
Conteneurs STLmap<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”;
container par défaut: vectorcompact, efficace, cache, préfetch
dictionary: map (arbre) ou unordered_map (hash)
vecteur de taillle fixe: arraycompact, efficace, cache, préfetch
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}// Forme préférée : begin() et end()for (auto i = begin(v); i != end(v); ++i) {…}
cbegin(), cend(), crbegin(), crend()
Parcours simples Exemple : for_each = le plus simple
Parcours avec transformations Exemple : copy = copie tous les éléments
répondant à une conditionTris Exemples : sort, stable_sort, lower_bound
Algorithmes : trois catégories
All ofAny ofNone ofFor eachFindFind endFind firstAdjacent FindCountMismatchEqualIs permutationSearch
Parcours simples
template<class InputIterator, class Predicate>InputIterator find_if(InputIterator first, InputIterator last, Predicate pred);
Retourne le premier élément vérifiant le prédicatPredicate : Fonctions Classe surchargeant operator() Lambda
Exemple : Find first
CopyMoveSwapTransformReplaceFillGenerateRemoveUniqueReverseRotateRandom shufflePartitions
Transformations
template<class InputIterator, class OutputIterator, class UnaryOperation>OutputIterator transform(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation op);
Exemple: impression de tous les éléments d’un conteneur :
copy(points.begin(), points.end(), ostream_iterator<CPoint>(cout, "\n" ));
Exemple Transform
SortStable_sortPartial_sortNth elementBinary search : lower_bound, upper_boundMerge
Tri et assimilés
template<class RandomAccessIterator, class Compare>void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
Trie les éléments selon « comp »Comp = ordre strict (< ou > et non £ ou ³)
bool PlusHaut(CPoint &pt1, CPoint &pt2){ return pt1.Y() > pt2.Y();}sort(points.begin(), points.end(), PlusHaut);
Exemple : sort
Function for_each(InputIterator first, InputIterator last, Function f);InputIterator find_if(InputIterator first, InputIterator last, Predicate pred);void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
Fonctions et prédicats
Fonctions simples :bool PlusHaut(CPoint &pt1, CPoint &pt2){ return pt1.Y() > pt2.Y();}
Classes surchargeant () :class DistancePoint {protected: const CPoint &_ptr;public: DistancePoint(const CPoint &ptr) : _ptr(ptr) {}
bool operator()(CPoint &pt1, CPoint &pt2) { return _ptr.Distance2(pt1) < _ptr.Distance2(pt2); }};
Et lambdas !
Les Lambda Expressions définissent et construisent des classes fonctions anonymesLa Lamba Expressionfor_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
Est équivalente àstruct LambdaFunctor { void operator()(int n) const { cout << n << " "; }};…for_each(v.begin(), v.end(), LambdaFunctor);
Le B.A. BA des lambdas
Une lambda peut contenir plusieurs instructionsvoid par 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 [&]
Compléments
C++ C#
47
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;}
Polygon Search(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
48
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;}
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;}
Maintenant, on peut écrire celavector<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 une fonction (souvent par un constructeur) qui accepte un argument std::initializer_list<T>
vector (std::initializer_list<E> s) // initializer-list constructor
Initialisation des listes
VC++ & C++11VC11Beta
VC11RTM
OOBCTP
OOBRTM
Feb2012
+ C++11range-for,
final,override
Out-Of-BandReleases
+ progressively roll out C++11 initializer lists, template
aliases, variadic templates, constexpr, noexcept,
=default/delete, …
VC11DP
Sep2011
+ completeC++11 stdlib:
thread/mutex,async, future, …+ track changes
(lambdas, &&, …)
Techdays 2012
VC10RTM
Apr2010
+ lambdas, move/&&,
auto, decltype,auto fn decls,
extern template,nullptr, … Survey: bit.ly/mscpp11
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_ptrCapitaliser sur les conteneurs et algorithmes de la STLIntégrer le déplacement dans les membres spéciaux
A retenir
Le standard C++ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3337.pdf
Channel 9 : Going Deep (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ître90 jours d’essai gratuit de Windows Azure www.windowsazure.fr
Jusqu’à 35% de réduction sur Visual Studio Pro, avec l’abonnement MSDN www.visualstudio.fr
Pour aller plus loin10
février 2012
Live Meeting
Open Data - Développer des applications riches avec le protocole Open Data
16 février 2012
Live Meeting
Azure series - Développer des applications sociales sur la plateforme Windows Azure
17 février 2012
Live Meeting Comprendre le canvas avec Galactic et la librairie three.js
21 février 2012
Live Meeting La production automatisée de code avec CodeFluent Entities
2 mars 2012
Live Meeting
Comprendre et mettre en oeuvre le toolkit Azure pour Windows Phone 7, iOS et Android
6 mars 2012
Live Meeting Nuget et ALM
9 mars 2012
Live Meeting Kinect - Bien gérer la vie de son capteur
13 mars 2012
Live Meeting Sharepoint series - Automatisation des tests
14 mars 2012
Live Meeting
TFS Health Check - vérifier la bonne santé de votre plateforme de développement
15 mars 2012
Live Meeting
Azure series - Développer pour les téléphones, les tablettes et le cloud avec Visual Studio 2010
16 mars 2012
Live Meeting
Applications METRO design - Désossage en règle d'un template METRO javascript
20 mars 2012
Live Meeting
Retour d'expérience LightSwitch, Optimisation de l'accès aux données, Intégration Silverlight
23 mars 2012
Live Meeting
OAuth - la clé de l'utilisation des réseaux sociaux dans votre application
Prochaines sessions des Dev Camps