Vous êtes sur la page 1sur 25

Ecole Nationale Supérieure de Techniques Avancées

Programmation scientifique en C++


SIM 201 Chapitre VII

C++ 2011

E. Lunéville
2022
Introduction
C++98 : fondements du C++ mais
 avec des défauts, certains palliés par le compilateur
 avec des manques, certains palliés par d'autres librairies (e.g. boost)
 et un manque de modernité que proposent d'autres langages !

C++11 : mise à jour majeure (compatibilité ascendante)


 publié en septembre 2011, norme ISO/IEC 14882:2011
 puis mises à jour plus mineures (C++14, C++17, C++20)
 C++11 est le mode par défaut des compilateurs (versions > ~2014)
 principales évolutions
o amélioration syntaxiques
o inférence de type (auto, decltype)
o liste d'initialisation, boucle
o du côté des classes (délégation, héritage des constructeurs, surcharge)
o du côté des template (template variadique, using)
o lambda fonctions
o right value et sémantique de déplacement (move)
o nouvelles classes dans la STL (tuple, regexp, aléatoire, chrono...)
SIM201– Chapitre 7 1
Améliorations syntaxiques
Le C++11 introduit quelques simplifications d'ordre syntaxique :
 pointeur nullptr
En C++98, le pointeur nul est défini par 0, soit un int. Ce qui peut poser des problèmes. La
norme C++11 introduit nullptr pour représenter le pointeur nul :

encore autorisé en C++11

nullptr n'est pas l'entier 0 !

 autres améliorations (voir documentation)


• prise en charge des caractères unicode : char16_t, char32_t
• définition d'expressions littérales avec l'opérateur ""
• union sans restriction (aux types primaires); attention limitation
• énumeration à typage fort (clés non littérales)
• sizeof étendu aux données membre non statiques

SIM201– Chapitre 7 2
attribut constexpr
Le C++11 introduit l'attribut constexpr plus fort que const :
il indique que la variable peut être évaluée à la compilation. S'applique à des variables
de type litteral qui doivent être initialisées :

erreur car i non initialisé


erreur car j n'est pas une constexpr

Une fonction peut être déclarée constexpr. Elle sera évaluée à la compilation si c'est
possible, sinon elle sera évaluée à l'exécution. C'est une fonction inline :

evalué à la compilation

permet de gagner du temps d'exécution !


SIM201– Chapitre 7 3
Inférence de type (auto)
Dans de nombreuses situations, le compilateur peut déduire le type d'une variable,
le C++11 introduit le mot clé auto pour indiquer que le type d'une variable doit être
déterminé par le compilateur :
auto var = ... doit être initialisée

Exemple avec affichage du type utilisant la fonction typeid (voir std::typeinfo)

type de j : i int impression console


type de r : d double
type de c : PKc pointeur d'un tableau de char
type de s : NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE string
type de pr : Pd pointeur de double
type de rr : d double
type de it : N9__gnu_cxx17__normal_iteratorIPdSt6vectorIdSaIdEEEE iterateur sur un vector<double>
SIM201– Chapitre 7 4
Inférence de type (auto)
Simplifie la vie du développeur, allège le code :

Le type est inféré à travers une fonction :

argument de retour auto

type de k : i
type de y : d impression console
type de fp : PFiiE pointeur de fonction int -> int

autre exemple :

argument d'entrée et de retour auto


SIM201– Chapitre 7 5
Inférence de type (auto, decltype)
auto fonctionne tant que le compilateur peut retrouver le type :
factoriel récursif

erreur de compilation : use of 'auto fact(const int&)' before deduction of 'auto'

auto est une commodité qui permet d'alléger le code (déclaration d'itérateurs en
particulier) mais attention il ne permet pas de s'affranchir de la connaissance
du type réel. Ne pas en abuser !

le C++11 introduit le mot clé decltype pour "récupérer" le type d'une variable
ou d'une expression, permettant ainsi de déclarer une variable du même type
qu'une autre :

decltype(i) ne s'imprime pas !


SIM201– Chapitre 7 6
Liste d'initialisation (initializer_list)
C++11 introduit les listes d'initialisation (items entre accolades) pour initialiser
des tableaux statiques :
OK dimensionnement du tableau par la liste
OK liste moins longue que le tableau (complété par 0)
erreur : liste trop longue !

Ces listes sont des objets de la classe template std::initializer_list<T>; on peut


donc les utiliser pour ses propres classes, en définissant le constructeur :

La classe std::initializer_list<T>
ne propose que les fonctions
size, begin, end

Construction d'un Vect avec liste d'initialisation

la classe std::vector<T> de la STL propose un constructeur avec liste d'initialisation


SIM201– Chapitre 7 7
Les boucles automatiques
Le C++11 introduit le concept de boucle automatique où il n'est plus nécessaire
de préciser les bornes de la collection :
for ( type var : collection ) {...}

liste explicite

vecteur de float

utilisation de auto, p est une pair<string,string>

noter l'initialisation de la map names utilisant une liste d'initialisation constituée de listes
d'initialisation
SIM201– Chapitre 7 8
Fonctions avec trailing type
Le C++11 introduit la possibilité de préciser le type de l'argument de retour après
la déclaration de la fonction (trailing type) en conjonction avec l'attribut auto

auto fun(args) -> type_retour

ici auto ne sert qu'à la syntaxe (pas de déduction de type)


Il est possible d'utiliser decltype

Son intérêt réside dans le cas où le type de l'argument de retour peut dépendre du type
des arguments d'entrées :

imin est de type int car le min est 1 (int)


fmin est de type double car le min est 3.5 (double)

SIM201– Chapitre 7 9
Du côté des classes
Le C++11 introduit quelques nouveautés pour la gestion classes
 Initialisation des données membre non statiques

non autorisé en C++98

 Délégation et héritage des constructeurs


on peut dorénavant appeler un autre constructeur depuis un constructeur (délégation) :

la classe Derive peut utiliser les


constructeurs de la classe Base
SIM201– Chapitre 7 10
Du côté des classes
 Surcharge explicite des fonctions membre virtuelles
Afin de limiter les erreurs dans les surcharges de fonctions virtiuelles, le C++11 introduit
deux nouveaux qualificateurs :
• override : indique que la fonction est une surchage
• final : indique que la fonction n'est pas surchargeable

non surchageable

erreur, f non surchagable


erreur, g ne dérive pas de A::g (défini const !)
ok C++98, aurait pu avoir l'attribut override
erreur, A::k() non virtuelle

pour des raisons de compatibilité ascendante, ces attributs restent optionnels !


SIM201– Chapitre 7 11
Du côté des classes
 Suppression des fonctions membre par défaut
Pour interdire l'utilisation de certaines fonctions par défaut (constructeur par copie, opérateur
=) on les déclare en privé en C++98. Le C++11 introduit le mot clé delete :

 Restauration des fonctions membre par défaut


Dès qu'un constructeur est déclaré, les constructeurs par défaut ne sont plus générés.
On peut les restaurer avec le mot clé default :

un constructeur quelconque
restauration des fonctions par défaut

Les attributs delete et default peuvent être utilisés sur toutes les fonctions susceptibles
d'être automatiquement créées, par exemple des fonctions de conversion.
SIM201– Chapitre 7 12
Du côté des classes
 Opérateur de conversion explicite
En C++98, les opérations de conversion peuvent être réalisées soit à l'aide de
constructeurs implicites ( appelés automatiquement par le compilateur) ou
explicites (appelés par l'utilisateur) ou d'opérateurs de conversion toujours
implicites

constructeur pour conversion int ->A implicite


constructeur pour conversion int ->A explicite
opérateur de conversion A->int implicite

En C++11, les opérateurs de conversion peut être déclarés explicit

opérateur de conversion A->int explicite

SIM201– Chapitre 7 13
Du côté des template
 les double chevrons
l'espace entre le chevrons <> dans le cas de classes template emboitées n'est plus obligatoire
interdit en C++98

 les alias de template (using)


Le C++98 n'autorise pas les alias (typedef) dans les template

ip est un int*
En C++11, on peut utiliser using à la place de typedef
alias sur un pointeur de fonction int -> void

 template argument par défaut et variadique


Le C++11 autorise dorénavant les types par défaut dans les template :

Les fonctions variadiques (nombre variable d'arguments) sont proposés en C++98,


mais pas pour les template. Cela est dorénavant possible en C++.

SIM201– Chapitre 7 14
Lambda fonction
Une lambda fonction est une fonction anonyme de syntaxe générale :

[capture] (args) [mutable] [exception][attribute] [-> type_retour] {...}

• args : liste des arguments d'entrée


• type_retour : type de l'argument retour (optionnel si détectable par le compilateur)
• capture : liste de variables extérieures (valeur/référence) accessibles par la fonction
(= toutes les variables par valeur, & toutes les variables par référence)
• mutable : la fonction peut modifier les variables capturées, appeler des membres non const
• exception : spécification d'un gestionnaire d'exception
• attribute : option supplémentaire dépendant des compilateurs tout est optionnel !

aucun argument

type de retour bool calculé

double converti en int !

paramètres n, pi non modifiables


paramètre n modifiable

SIM201– Chapitre 7 15
Lambda fonction
Stocker une lambda fonction et la réutiliser :

Les algorithmes de la STL supportent les lambda fonctions :

lambda fonction transmise

• Les lambda fonctions sont destinées à être utilisées localement contrairement aux
fonctions usuelles à portée globale.
• Plus rapides car elles sont par principe inline
• L'intérêt des lambda fonctions est leur capacité à capturer par référence ou valeur des
objets de la portée englobante (paramètres).
• Concept moderne issu de la programmation fonctionnelle et répandu dans les langages
plus récents (python, C#, java, ...)

SIM201– Chapitre 7 16
Référence sur des right values
left value : expression assignable (adresse mémoire accessible)
souvent une variable stockée en mémoire
une variable const est une left value non modifiable
right value : expression non assignable (adresse mémoire non accessible)
en général un résultat temporaire souvent stocké dans les registres

terminologie issue de la syntaxe d'assignation L = R (L assignable, R assignable ou non)

ok : i est une lvalue


erreur : 7 n'est pas une lvalue
erreur : j*4 n'est pas une lvalue (c'est une rvalue)
ok : un pointeur déréférencé est une lvalue
ok mais ci est une lvalue non modifiable par la suite
ok l'opérateur conditionnel retourne une lvalue (i ou j)

1 (littéral) est une rvalue


1+x (résultat temporaire) est une rvalue

classification plus fine en C++11 (sous catégories prvalue, xvalue, glvalue) voir
https://en.cppreference.com/w/cpp/language/value_category
SIM201– Chapitre 7 17
Référence sur des right values
Sémantique de déplacement (move) :
consiste à proposer un moyen de déplacer des objets sans les copier
si le contexte le permet, en particulier dans le cas d'objets temporaires!
Le C++98 ne le permet pas : objet temporaire recopié puis détruit !

Le C++11 introduit la notion de référence sur une right value (entité temporaire
qui va être détruite) avec la notation &&. En définissant un constructeur
agissant sur de telles références, on peut déplacer les objets temporaires
sans les copier :

constructeur par copie (usuel)


copie du vecteur !

constructeur par déplacement (move)


copie du pointeur !

même principe avec


l'opérateur d'assignation =
SIM201– Chapitre 7 18
Référence sur des right values

Le compilateur appelle automatiquement le constructeur par déplacement (si il existe)


sur des objets de type rvalue et le constructeur par copie sur des objets de type lvalue.

Dans certaine situation, les objets sont de type lvalue mais ont un caractère temporaire.
La fonction de la STL std::move permet de les réinterpréter comme des rvalue :

C++98, copie C++11, déplacement

copie de x -> z déplacement de x -> z


copie de y -> x déplacement de y -> x
copie de z -> y déplacement de z -> y
3 copies !
ici, x, y , z ne sont pas considérés revient à faire un swap des pointeurs !
comme des objets temporaires ! T doit proposer un constructeur et un opérateur =
par déplacement

Penser à faire le constructeur et l'opérateur =


par déplacement si les objets sont volumineux

SIM201– Chapitre 7 19
Extensions de la STL
Nombreuses extensions dans la STL (voir documentation en ligne). Ici, seulement un aperçu
des principales nouvelles classes :
 Classe thread, entête <thread>, importée de la librairie Boost

exemple

crée un thread et exécute f


crée un thread et exécute g(0)
attend la fin du thread th1
attend la fin du thread th2

 Classe tuple, entête <tuple>, collection d'objets de types quelconques différents


alias
objet tuple avec liste d'initialisation
récupère la string en position 2
modifie l'entier en position 0
généralisation de pair, basée sur les template variadiques !
SIM201– Chapitre 7 20
Extensions de la STL
 Classe regex, entête <regex>, gestion des expressions régulières (grammaire ECMAScript)
fonctions rattachées (regex_match, regex_search, regex_replace)

vérification de conformité

expression commençant par sub

 classe system_clock, entête <chrono>, outils de temps de calcul (namespace std::chrono)

le namespace chrono appartient au namespace std


SIM201– Chapitre 7 21
Extensions de la STL
 Génération de nombres aléatoires, entête <random> propose
• des classes pour différentes lois de distribution : uniforme, Bernouilli, geometric, Poisson,
binomial, exponentielle, normale, gamma
• des algorithmes de générations (moteur) : linear_congruential, mersenne_twister,
substract_with_carry

exemple

objet distribution uniforme


générateur Mersenne twister
retourne un échantillon

 Table de hachage (unordered), collection avec indexation numérique des clés (hash)
• classes unordered_set, unordered_multiset, entête <unordered_set>
• classes unordered_map, unordered_multimap, entête <unordered_map>
• fonction de hachage par défaut, peut être modifiée
• proposent la même chose que les classes set, map, multiset, multimap
• map : insertion, recherche, supression en O(log(n)); parcours ordonné selon les clés
• unordered_map : insertion, recherche, supression en O(1) en moyenne, en O(n) au
pire; parcours non ordonné

unordered_map en général plus rapide que map mais perte de l'ordre !


SIM201– Chapitre 7 21
C++14, C++17, C++20
 C++14 évolutions mineures relatives à
• lambda fonction
• constexpr
• déduction de type
 C++17 évolutions plus importantes relatives à
• template
• tuple syntax
• lambda function (constexpr)
• STL (variant, string_view, filesystem, fonctions spéciales)
 C++20 évolutions importantes
• introduction des concepts, modules, coroutines
• nombreuses extensions et ajouts à la STL
• voir https://en.cppreference.com/w/cpp/20
support des compilateurs (* partiel)
GCC Visual Studio CLANG ICC
version C++
(GNU) (Microsoft) (MacOS) (Intel)
11 4.8.1 2015 3.3 15
14 5.1 2015 3.4 16*
17 5.1 2019 5 19
20 8* 9*
SIM201– Chapitre 7 22
Conclusion

Nombreux apports du C++11

 liste d'initialisation, facile à utiliser


 inférence de type (auto); de l'ordre de la commodité, ne pas en abuser !
 sémantique de déplacement (move) et référence sur rvalue, indispensable
pour des objets volumineux
 lambda functions (portée locale, capture de paramètres), pas indispensable
 renforcement de la robustesse des classes (override, final, default), facile à
mettre en oeuvre
 nouvelles classes de la STL : tuple, system_clock, unordered_map,
générateurs aléatoires, thread

Certains concepts plus difficiles requièrent


une maîtrise des fondamentaux du C++98

SIM201– Chapitre 7 23

Vous aimerez peut-être aussi