Le langage C++ a toujours la réputation d’un langage complexe, demandant une rigueur de tous les instants et qui peut en rebuter plus d’un. Mais avec l’arrivée de la nouvelle norme C++11 et de son intégration dans Visual Studio 11 (et intégration partielle dans Visual Studio 2010), elle permet comme le souligne Herb Sutter, d’écrire désormais du code "Clean, Safe and Fast", nous passons à l'ère du C++ moderne.
2. Les nouveautés de C++
Ecrire du code C++ Moderne (LAN207)
Christophe Pichaud Alain Zanchetta
Consultant Architecte Consultant Architecte
Sogeti Microsoft
4. 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
5. 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
6. 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 »)
8. C++, mythes et réalités
principes et techniques gestion des erreurs
pointers
Code crado mais je continue
Un langage orienté objet cast
sur le même modèle…
compliqué !
Orienté objet Compliqué à apprendre !
Des macros et de goto !
Peu productif ! Structure de données
Bas niveau ! Interfaces riches compactes et efficaces
Non sécurisée, dangereux ! Template meta-programming
C’est du C ! Code dur à maintenir
new / delete
Un bon code le style C++ 11
10. Illustration
Soit un 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++
11. C++ « classique » C#
CPolygon *Search(int x, int y) Polygon Search(int x,
{
CPoint pt(x,y); int y)
vector<CPolygon*> polys; {
ReadPolys(polys);
CPolygon *ret = NULL; Point pt
for (vector<CPolygon*>::iterator = new Point(x,y);
beg = polys.begin();
beg!=polys.end();++beg) { List<Polygon> polys
if ((*beg)->Contains(pt)) { = ReadPolys();
ret = *beg;
break; return polys.FirstOrDefault(
} p => p.Contains(pt));
}
for (vector<CPolygon*>::iterator }
beg = polys.begin();
beg!=polys.end();++beg)
if ((*beg) && (*bet != ret)) delete *beg;
return ret;
}
11
12. 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
class widget { Gestion automatique void f() { du membre gadget w.g.
du cyle de vie lié à widget w;
private: l’objet contenant
gadget g; :::
public: w.draw();
void draw(); ::: Destruction
}; } automatique et de-
allocation de w et w.g
13. Libération dé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
14. Caractéristiques de
shared_ptr<T> dans <memory>
Un template C++ disponible
shared_ptr<Polygon> sp(new Polygon());
sp->Draw(…);
return sp;
Basé sur le comptage de références
Gain de productivité & robustesse importants 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ération particulière :
shared_ptr<int> sp((int*)CoTaskMemAlloc(sizeof(int)),
CoTaskMemFree);
15. shared_ptr est Non-Intrusif
Possibilité d’instancier shared_ptr<T> sans modifier T
La gestion des références (uses/weaks) est dans le
shared_ptr
Fonctionne avec les types prédéfinis: shared_ptr<int>
S’incorpore dans le code sans modifier les types existants
Un même type peut être manipulé parfois via un
shared_ptr et d’autres fois via d’autres mécanismes
16. 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);
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
17. 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
static void do_lock (const char *title, weak_ptr<resource> wp)
{
shared_ptr<resource> sp = wp.lock();
show(title, sp);
} int main()
{
int main() // demonstrate member function expired
{ cout << boolalpha;
// demonstrate member function lock shared_ptr<resource> sp(new resource);
shared_ptr<resource> sp0(new resource); weak_ptr<resource> wp(sp);
weak_ptr<resource> wp0(sp0); cout << "points to resource: " << wp.expired () << 'n';
do_lock("weak_ptr with resource", wp0); sp.reset ();
sp0.reset(); cout << "expired: " << wp.expired() << 'n';
do_lock("expired weak_ptr", wp0); return 0;
return 0; }
}
18. unique_ptr<T>
Une seule référence de l’objet
unique_ptr<Cat> c(new Cat);
unique_ptr<Cat> c2(Cat::Load(…));
Remplace auto_ptr, qui est obsolète
Compatible 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));
19. 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."
24. auto
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#
25. auto: pourquoi l’utiliser ?
auto utilise les règles de détection d’arguments des
templates
const auto * p = foo et const auto& r = bar compilent
auto...
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
26. C++ C#
shared_ptr<CPolygon> Search(int x,
int y)
Polygon Search(int x,
{ int y)
CPoint pt(x,y); {
vector<shared_ptr<CPolygon>> polys; Point pt
ReadPolys(polys);
for (vector<shared_ptr<CPolygon>>:: = new Point(x,y);
for (auto beg = beg = polys.begin();
iterator polys.begin(); List<Polygon> polys
beg!=polys.end();
beg != polys.end(); = ReadPolys();
++beg) { {
++beg)
if ((*beg)->Contains(pt))
return polys.FirstOrDefault(
return *beg; p => p.Contains(pt));
} }
return nullptr;
}
27. Move Semantics, Perfect
Forwarding n’est pas LValue deux choses importantes :
RValue = tout ce qui
Les références de Rvalue permettent
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_shared
Les patterns de déplacement et de perfect forwarding sont simples à mettre en
oeuvre
Mais 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”
28. Mécanique du Move / Value Types
class my_class { my_class f()
BigHugeData *data; {
public: my_class tmp;
my_class(const my_class& src) …
{ return tmp;
… }
}
my_class(my_class&& other) void main()
{ {
data = other.data; my_class c = f();
other.data = nullptr; }
}
…
}; Appel du Move Constructor
29. C++ C#
shared_ptr<CPolygon> Search(int x,
int y)
Polygon Search(int x,
{ int y)
CPoint pt(x,y); {
auto polys = ReadPolys(polys);
vector<shared_ptr<CPolygon>> polys; Point pt
ReadPolys(polys);
for (auto beg = polys.begin(); = new Point(x,y);
beg != polys.end(); List<Polygon> polys
++beg) { = ReadPolys();
if ((*beg)->Contains(pt))
return *beg;
return polys.FirstOrDefault(
} p => p.Contains(pt));
return nullptr; }
}
29
30. Une classe C++11 type
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
31. =default et =delete
Indiquer explicitement un opérateur de copie par défault
class Y {
// ...
Y& operator=(const Y&) = default; // default copy semantics
Y(const Y&) = default;
}
Indiquer l’interdiction de la copie
class X {
// ...
X& operator=(const X&) = delete; // Disallow copying
X(const X&) = delete;
};
33. 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
}
// Forme préférée : begin() et end()
for (auto i = begin(v); i != end(v); ++i) {
…
}
34. 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
35. Parcours simples
All of
Any of
None of
For each
Find
Find end
Find first
Adjacent Find
Count
Mismatch
Equal
Is permutation
Search
36. Exemple : Find first
template<class InputIterator, class Predicate>
InputIterator find_if(InputIterator first,
InputIterator last,
Predicate pred);
Retourne le premier élément vérifiant le prédicat
Predicate :
Fonctions
Classe surchargeant operator()
Lambda
37. Transformations
Copy
Move
Swap
Transform
Replace
Fill
Generate
Remove
Unique
Reverse
Rotate
Random shuffle
Partitions
38. Exemple Transform
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" ));
39. Tri et assimilés
Sort
Stable_sort
Partial_sort
Nth element
Binary search : lower_bound, upper_bound
Merge
40. Exemple : sort
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);
41. Fonctions et prédicats
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 simples : Classes surchargeant () :
bool PlusHaut(CPoint &pt1, class DistancePoint {
protected:
CPoint &pt2) const CPoint &_ptr;
{ public:
return pt1.Y() > pt2.Y(); DistancePoint(const CPoint &ptr)
} : _ptr(ptr) {}
bool operator()(CPoint &pt1,
CPoint &pt2) {
Et lambdas ! return _ptr.Distance2(pt1)
< _ptr.Distance2(pt2);
}
};
42. 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 à
struct LambdaFunctor {
void operator()(int n) const {
cout << n << " ";
}
};
…
for_each(v.begin(), v.end(), LambdaFunctor);
43. Compléments
Une lambda peut contenir plusieurs instructions
void 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 [&]
44. C++ C#
shared_ptr<CPolygon> Search(int x, Polygon Search(int x,
int y)
int y)
{
CPoint pt(x,y); {
auto polys = ReadPolys(polys);
ReadPolys(); Point pt
auto found = find_if(begin(polys), = new Point(x,y);
for (auto beg = polys.begin();
end(polys), List<Polygon> polys
[pt](shared_ptr<CPolygon> pol) {
beg != polys.end(); = ReadPolys();
return++beg) {
pol->Contains(pt); return polys.FirstOrDefault(
});
if ((*beg)->Contains(pt)) p => p.Contains(pt));
return (found != polys.end())
return *beg;
}
} ? *found : nullptr;
} return nullptr;
}
44
45. C++ 98 C++ 2011
CPolygon *Search(int x, int y) shared_ptr<CPolygon> Search(int x,
{ int y)
CPoint pt(x,y); {
vector<CPolygon*> polys;
ReadPolys(polys);
CPoint pt(x,y);
CPolygon *ret = NULL; auto polys = ReadPolys();
for (vector<CPolygon*>::iterator auto found = find_if(begin(polys),
beg = polys.begin(); end(polys),
beg!=polys.end();++beg) { [pt](shared_ptr<CPolygon> pol) {
if ((*beg)->Contains(pt)) { return pol->Contains(pt);
ret = *beg; });
}
}
return (found != polys.end())
for (vector<CPolygon*>::iterator ? *found : nullptr;
beg = polys.begin(); }
beg!=polys.end();++beg)
if ((*beg) && (*bet != ret)) delete
*beg;
return ret;
} 45
46. Initialisation des listes
Maintenant, on peut écrire cela
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 une fonction (souvent par un
constructeur) qui accepte un argument std::initializer_list<T>
vector (std::initializer_list<E> s) // initializer-list constructor
48. 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
49. Pour aller plus loin
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/
50. Pour aller plus loin
Chaque semaine, les DevCamps Prochaines sessions des Dev Camps
10 février Open Data - Développer des applications riches avec le protocole Open
Live Meeting
ALM, Azure, Windows Phone, HTML5, OpenData 2012 Data
http://msdn.microsoft.com/fr-fr/devcamp 16 février
2012
Live Meeting
Azure series - Développer des applications sociales sur la plateforme
Windows Azure
17 février
Live Meeting Comprendre le canvas avec Galactic et la librairie three.js
2012
Téléchargement, ressources et 21 février
2012
Live Meeting La production automatisée de code avec CodeFluent Entities
toolkits : RdV sur MSDN 2 mars
2012
Live Meeting
Comprendre et mettre en oeuvre le toolkit Azure pour Windows Phone 7,
iOS et Android
http://msdn.microsoft.com/fr-fr/
6 mars
Live Meeting Nuget et ALM
2012
Les offres à connaître
9 mars
Live Meeting Kinect - Bien gérer la vie de son capteur
2012
13 mars
90 jours d’essai gratuit de Windows Azure 2012
Live Meeting Sharepoint series - Automatisation des tests
www.windowsazure.fr 14 mars
2012
Live Meeting
TFS Health Check - vérifier la bonne santé de votre plateforme de
développement
15 mars Azure series - Développer pour les téléphones, les tablettes et le cloud
Jusqu’à 35% de réduction sur Visual Studio 2012
Live Meeting
avec Visual Studio 2010
Pro, avec l’abonnement MSDN 16 mars
2012
Live Meeting
Applications METRO design - Désossage en règle d'un template METRO
javascript
www.visualstudio.fr 20 mars
Live Meeting
Retour d'expérience LightSwitch, Optimisation de l'accès aux données,
2012 Intégration Silverlight
23 mars
Live Meeting OAuth - la clé de l'utilisation des réseaux sociaux dans votre application
2012