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

Post on 24-Feb-2016

32 views 0 download

description

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 - PowerPoint PPT Presentation

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