Articulé autour de C++ 11, cette session amène celui qui y assiste aux fondamentaux du développement logiciel : libraries, dépendances, TR1 et C++0X les fondations de C++ 11, runtime C alias CRT, runtime C++ alias STL, agilité en C++, ALM en C++, Windows 8 et C++, C++ et Windows 8 avec le nouveau modèle COM nommé WRL.
1. Développement natif en
C++
Christophe Pichaud – Architecte
Sogeti
Loïc Joly – Architecte
CAST
Code / Développement
2.
3. Chapitre 1
C++11 LES GRANDS THÈMES
Développement natif en C++ 11
4. Pourquoi une session C++ ?
C++11 est comme un nouveau langage
Evolutions du langage – standard C++ 11
Changer le codage avec des styles/guidances/idioms.
C’est ce qui définit le nouveau langage
5. Pourquoi le C++ ?
Optimiser Exemple C++ ?
Le temps/coût de développement Interface d’accès BdD Non
Le temps d’exécution Jeux, temps réel Oui
Le coût hardware Ferme de serveurs Oui
L’énergie nécessaire Informatique mobile Oui
Centre de calcul
• Dans de nombreux domaines, le coût de développement
est devenu très faible face au coût d’exploitation
6. 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
7. La roadmap 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 »)
9. C++, mythes et réalités
principes et techniques gestion des erreurs
pointeurs
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. Evolution du style C++
Le C++11 permet de faire du code Clean, Safe,
Fast.
Clean & Safe : le nouveau style moderne
Fast : l’a toujours été
11. Aperçu des différences
auto type deduction T* shared_ptr<T>
Then Now new
return by value + move
make_shared
circle* p = new circle( 42 ); + auto again to deduce auto p = make_shared<circle>( 42 );
vector<shared_ptr<shape
vector<shape*> vw; auto vw = load_shapes();
>>
load_shapes( vw ); for( auto& s : vw ) {
range-for
for( vector<circle*>::iterator i = vw.begin(); i != vw.end(); if( s->weight() > 100 )
++i ) { cout << *s << “ is a matchn”;
if( (*i)->weight() > 100 ) }
cout << **i << “ is a matchn”;
}
for( vector<circle*>::iterator i = vw.begin();
i != vw.end(); ++i ) {
delete *i; not exception-safe Pas de delete. Gestion
}
missing try/catch, automatique du cycle de vie.
delete p;
__try/__finally exception-safe
12. Gestion de la mémoire
Plus grosse « difficulté du C++ » : la gestion de mémoire
Il n’y a pas de manière unique d’allouer la mémoire en C++
Heureusement : RAII= Resource Acquisition Is Initialization
Destruction déterministe (i.e. pas besoin de « using »)
Applicable à toutes les ressources « précieuses :
Mémoire
fichiers, sockets, handles Windows
“C++ is the best language for garbage collection principally
because it creates less garbage.”
Bjarne Stroustrup
13. 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."
14. Caractéristiques de
shared_ptr<T>
Un template C++ disponible dans <memory>
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
Besoin de convertir (cast) ?
static_pointer_cast<Derived>(spBase)
dynamic_pointer_cast<Derived>(spBase)
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):
auto sp = make_shared<T>(args);
auto sp = allocate_shared<T>(alloc, args);
Simple et élegant
Écrire le type T une seule fois
Robuste
Pas de fuite avec shared_ptr
Efficace
Allocation de mémoire dynamique standard
17. 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));
21. Boucle for avec range
Itération au travers un “range”
void f(vector<double>& v)
{
for (auto x : v)
cout << x << 'n';
for (auto& x : v)
++x; // using a reference to allow us to change the value
}
22. nullptr
nullptr exprime un pointeur nul
Ce n’est pas un int
class Foo {
public:
Foo(const char *s);
Foo(int n);
}
…
Foo f(NULL);
Foo f(nullptr);
24. Syntax Error de template<T>
La problème d’espace est résolu
list<vector<string>> lvs;
25. 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
Conseil
si vous implémentez une de ces méthodes, alors implémentez-les
toutes.
26. enum & enum classclass enum
Conversion de enum automatiquement en int et enum fortement typé
enum Alert { green, yellow, election, red }; // traditional enum
enum class Color { red, blue }; // scoped and strongly typed enum
// no export of enumerator names into enclosing scope
// no implicit conversion to int
enum class TrafficLight { red, yellow, green };
Alert a = 7; // error (as ever in C++)
Color c = 7; // error: no int->Color conversion
int a2 = red; // ok: Alert->int conversion
int a3 = Alert::red; // error in C++98; ok in C++0x
int a4 = blue; // error: blue not in scope
int a5 = Color::blue; // error: not Color->int conversion
Color a6 = Color::blue; // ok
27. =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;
};
28. constexpr
Le mécanisme de constexpr
Permet d’exprimer généralement des expressions
constantes
Permet d’utiliser les types spécifiques
Fournit l’assurance que l’initialisation est fournie au
moment de la compilation
Attention
constexpr ne remplace pas const (et vice versa)
29. decltype(E)
Le mécanisme de decltype(E) permet d’avoir une
expression qui peut être utilisée dans une déclaration
Concept utilisé en programmation générique
Appelée aussi “typeof”
Conseil
Préférez l’utilisation de auto
30. 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
31. Délégation de constructeur
Si deux ctor font la même chose, il faut une routine init() et faire
un appel dans chaque ctor…
Maintenant, il est possible décrire cela
class X {
int a;
public:
X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
X() :X{42} { }
X(string s) :X{lexical_cast<int>(s)} { }
// ...
};
32. Init. de membres de classes
Seules les membres statiques peuvent être initialisés et avec des
expressions constantes…
Maintenant, il est possible décrire cela
class A {
public:
A() {}
A(int a_val) : a(a_val) {}
A(D d) : b(g(d)) {}
int a = 7;
int b = 5;
private:
HashingFunction hash_algorithm{"MD5"}; // Cryptographic hash to be applied to all A
instances
std::string s{"Constructor run"}; // String indicating state in object lifecycle
};
33. long long (64 bits)
Un type long mais qui est very long.
Au moins 64 bits
long long x = 9223372036854775807LL;
34. template typedef
Un typedef pour les templates
Permet une écriture plus élégante des templates dans le
code
template<class T>
using Vec = std::vector<T,My_alloc<T>>; // standard vector using my allocator
Vec<int> fib = { 1, 2, 3, 5, 8, 13 }; // allocates elements using My_alloc
Marche aussi avec le code style-C
typedef void (*PFD)(double); // C style
using PF = void (*)(double); // using plus C-style type
35. auto
Avant…
vector<shared_ptr<CPolygon>>::iterator beg = polys.begin();
long et fastidieux à écrire !
Maintenant, avec « auto »
auto i = polys.begin();
Type déduit par le compilateur
Equivalent de « var » en C#
Evite aussi certaines conversions implicites en cas d’erreur
sur le type
36. auto
map<string, string> m;
const regex r("(w+) (w+)");
for (string s; getline(cin, s); ) {
smatch results;
if (regex_match(s, results, r)) {
m[results[1]] = results[2];
}
}
for (auto i = m.begin(); i != m.end(); ++i) {
cout << i->second << " are " << i->first << endl;
}
// Au lieu de map<string, string>::iterator
37. 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 le code et améliore la lisibilité du code important
Permet d’éviter les erreurs de types, troncations, …
Améliore la généricité du code sans le superflu des
expressions intermédiaires
Fonctionne très bien avec les types comme les lambdas
38. 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.cbegin(); i != v.cend(); ++i) {
// i is vector<int>::const_iterator
}
39. Références de RValue
Les 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_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”
40. Efficacité du déplacement
set<widget> load_huge_data() { vector<string> v = IfIHadAMillionStrings();
set<widget> ret; v.insert( begin(v)+v.size()/2, “tom” );
// … load data and populate ret … v.insert( begin(v)+v.size()/2, “richard” );
v.insert( begin(v)+v.size()/2, “harry” );
return ret;
}
Efficace, pas de
widgets = load_huge_data(); copie en profondeur
HugeMatrix operator+(
const HugeMatrix&, (juste les
Efficace: pas de copie en
const HugeMatrix& assignements de
);
profondeur et pas besoin hm3 = hm1+hm2;
pointeurs
du contournement
allocation dynamique +
Efficace, pas de copie
retour de pointeur
supplémentaire
41. Mécanique du Move / Value Types
class my_class {
unique_ptr<BigHugeData> data; move construction
public:
my_class( my_class&& other )
: data( move( other.data ) ) { }
my_class& operator=( my_class&& other )
{ data = move( other.data ); }
:::
void method() { move assignment
if( !data ) throw “moved-from object”;
:::
} Copy ? Move: Also enable move
check (if appropriate)
}; if it can be cheaper than a deep copy.
Move / Copy: Some non-value types
are naturally move-only. Example:
unique_ptr.
43. 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
44. Parcours simples
All of
Any of
None of
For each
Find
Find end
Find first
Adjacent Find
Count
Mismatch
Equal
Is permutation
Search
45. 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 prédéfinies
Classe surchargeant operator()
Lambda
46. Transformations
Copy
Move
Swap
Transform
Replace
Fill
Generate
Remove
Unique
Reverse
Rotate
Random shuffle
Partitions
47. 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" ));
48. Tri et assimilés
Sort
Stable_sort
Partial_sort
Nth element
Binary search : lower_bound, upper_bound
Merge
49. 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);
50. Lambdas
Fonctions simples
pas paramétrables
Classes
Lourdes à écrire
Pb de localité
Lambdas
Le meilleur des deux mondes
51. 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());
52. Compléments
Une lambda peut contenir plusieurs instructions
void par défaut
Lambda Stateless: [] signifie pas de capture du contexte
Capture-list : 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());
Les copies capturées « survivent » à leur contexte
Possibilité de capture par référence
53. 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
54. Délégation de constructeur
Si deux ctor font la même chose, il faut une routine init() et faire
un appel dans chaque ctor…
Maintenant, il est possible d’écrire cela
class X {
int a;
public:
X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
X() :X{42} { }
X(string s) :X{lexical_cast<int>(s)} { }
// ...
};
55. Init. de membres de classes
Seules les membres statiques peuvent être initialisés et avec des
expressions constantes…
Maintenant, il est possible d’écrire cela
class A {
public:
A() {} A(int a_val) : a(a_val) {}
A(D d) : b(g(d)) {}
int a = 7;
int b = 5;
private:
HashingFunction hash_algorithm{"MD5"}; // Cryptographic hash to be applied to all A
instances
std::string s{"Constructor run"}; // String indicating state in object lifecycle
};
56. Chapitre 2
TESTS UNITAIRES DANS VISUAL
STUDIO
Développement natif en C++ 11
57. Tests unitaires natifs
• Tests unitaires 100% natifs intégrés à l’IHM
• Framework de test
– Fourni par Microsoft
– Google tests
– xUnit++
– Autre ?
blogs.msdn.com/b/bhuvaneshwari/archive/2012/03/13/auth
oring-a-new-visual-studio-test-adapter.aspx
• Couverture de code
59. Chapitre 3
VISUAL C++11 ET NOV 2012 CTP
Développement natif en C++ 11
60. Visual C++ compiler Nov 2012 CTP
• CTP = Version version beta
– Incomplet : Uniquement le compilateur (pas la SL)
– Pas pour utilisation en prod
– Bugs possibles
– Activé explicitement
• 6 nouveautés
• Des démos !
61. Visual C++ compiler Nov 2012 CTP
• 6 nouveautés
– Littéraux de chaîne de caractères bruts
– Initialisation uniforme et initializer_lists
– Délégation de constructeurs
– Opérateurs de conversion explicites
– Templates variadiques
– Arguments template par défaut pour les fonctions
template
62. Visual C++ compiler Nov 2012 CTP
• Bénéfices
– Code C++ plus simple, plus rapide à écrire
– Meilleure compatibilité avec gcc, clang…
• Code portable avec moins de restrictions
• Plus large choix de bibliothèques
• À quand la version finalisée ?
• Le chemin n’est pas fini…
65. Exemple de code
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="App3.GroupedItemsPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource
Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App3"
xmlns:data="using:App3.Data"
xmlns:common="using:App3.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
Developpement
66.
67. Exemple de graphe
• Exemple
de Pie
chart
pour une
session
Réseaux
Réseaux
68.
69.
70.
71.
72.
73.
74.
75.
76.
77. Développeurs Pros de l’IT
http://aka.ms/generation-app Formez-vous en ligne www.microsoftvirtualacademy.com
http://aka.ms/evenements-
developpeurs Retrouvez nos évènements http://aka.ms/itcamps-france
Les accélérateurs
Faites-vous accompagner
Windows Azure, Windows Phone,
gratuitement
Windows 8
Essayer gratuitement nos http://aka.ms/telechargements
solutions IT
La Dev’Team sur MSDN Retrouver nos experts L’IT Team sur TechNet
http://aka.ms/devteam Microsoft http://aka.ms/itteam
Notes de l'éditeur
Intro code / dev
Les blocs de couleurs sont éditables et peuvent reprendre la couleur du type de session qui est donnée.Idem pour les textes.
Périphériques variés, avec processeur moins puissant que les PC classiquesVolonté de ne pas gaspiller les ressources pour préserver l’autonomie(Dans une certaine mesure) portabilitéCertains algorithmes demandent du CPU : exemple réalité augmentée
Quasiment rien de nouveau entre 1998 et 2005TR1 : apporte déjà pas mal de conceptsNorme téléchargeable : payante mais dernier draft avant ou premier après sont gratuits et ok
On ne couvrira pas tous les concepts mais ceux qui semblent essentiels, y compris s’ils viennent du TR1
Point négatif : la gestion de mémoire est difficiledifficile d’éviter les fuites, les doubles libérations, l’utilisation de zones déjà libéréesPoint positif : on va pouvoir s’appuyer sur RAII pour contrôler les différents types de libérationRAII = cfwikipedia (détailsslide suivante)
Facile de faire un « smartpointer » simple sur ce principe et il y a donc beaucoup de classes de libération des ressources basées sur ce mécanisme : smartpointers COM (qui ne font que libérer la référence), CFont, etcMais ce n’est pas suffisant quand le cycle de vie de l’objet est plus complexe : par exemple, retourné par une fonction et donc conservé au-delà de son scope d’initialisationTR1 a apporté plusieurs classes de smartpointers pour gérer les scénarios plus compliqués, et en particulier le shared_ptr qui permet à l’entité allouée de survivre au-delà de son scope d’allocation tout en étant gérée parfaitement
Comptage de références :Tant que l’objet est référencé, il n’est pas libéréLes surcharges des différents opérateurs du shared_ptr gèrent ce comptage de référence, typiquement :Copie d’un SP => + 1Destruction d’un SP => -1Et quand le nb de références atteint 0, l’objet est libéréCompatible avec les conteneurs STL : typiquement, on a un vecteur de shared_ptr qui est supprimé, les éléments le sont aussi (enfin, les shared_ptr aussi et les objets pointés si cela se justifie)
Le comptage est à l’extérieur de l’objet pointéDu coup tout les types sont compatibles, qu’il s’agisse de types pré-définis ou de classes de vos projets
La façon privilégiée d’allouer + stocker immédiatement un objetNote : le constructeur permet aussi de préciser la fonction de désallocation (qui peut être une lambda), ce qui permet par exemple de stocker un objet COM (qu’on ne libère pas par delete)
Unique_ptr = autre sémantique = une seule copie de l’objetDans l’exemple plus haut Cat::Load() est par exemple du code existant qui retourne un pointeur sur Cat…A utiliser par exemple avec le pattern pimplPas de make_unique() dans C++ 11 mais trouvable sur le site de Sutter (guru of the week)
Au final, avec lestroissmartpointersqu’on a vu, on peutcomplètement se passer de delete
Dans l’exemple précédent, j’ai utilisé nullptr à la place de NULL, c’est aussi une des améliorations du C++.Quiz : quel constructeur est appelé dans l’exemple de la slide ?Anecdote : il semblerait que la norme autorise de faire #define NULL nullptr mais un des gars de l’équipe de VC++ (STL) a fait le test et a trouvé plein de constructions qui ne marchaient plus dans Studio (y compris quelques fautes de frappe avec NUL)
Au final, avec lestroissmartpointersqu’on a vu, on peutcomplètement se passer de delete
TODO : supprimer cette slide et la remplacer par la suivante
BASCULE Christophe
Les blocs de couleurs sont éditables et peuvent reprendre la couleur du type de session qui est donnée.Idem pour les textes.
Les blocs de couleurs sont éditables et peuvent reprendre la couleur du type de session qui est donnée.Idem pour les textes.