Vous êtes sur la page 1sur 90

Programmer avec la librairie standard C++

Introduction à boost
Ressources
y The C++ Standard Library, a tutorial and reference, Nicolai M.
Josuttis, Addison Weslley.
y Beyond the c++ Standard Library, an introduction to boost,
Björn Karlsson, Addison Wesley.
y http://cs.stmarys.ca/~porter/csc/ref/cpp_standlib.html
y http://gcc.gnu.org/onlinedocs/libstdc++/manual/spine.html
y http://msdn.microsoft.com/en-us/library/cscc687y(VS.8
0).aspx
y http://www.boost.org/
Composantes de la librarie

y Utilitaires : Paires, limites, functions auxiliaires,


opérateurs de comparaison, auto_ptr, fichiers C.
y Exceptions
y Streams (flots)
y STL (Standard Template Library)
y Contenneurs
y Itérateurs
y Algorithms
y Strings
Toutes les classes et fonctions de la bibliothèque
standard appartiennent au namespace std::

Les fichiers en-tête de la bibliothèque standard ne


portent pas d’extension .
#include <iostream>
Fichier en-tête standard
int main()
{
std::cout << "Hello World\n";
}
Namespace
Paires

y Cette famille de classes permet de représenter des paires


de valeurs.
y On déclare une paire en utilisant pair<T1,T2> où T1 et T2
sont des types.
y Le constructeur par défaut crée une paire où les deux
valeurs sont crées avec le constructeur par défaut des
types respectifs (T1 et T2).
y Les membres first et second permettent d’accéder
respectivement à la première et à la deuxième valeur.
Paires
y La famille de fonctions make_pair(x,y) permet de créer à
la volée une paire, le type du résultat dépend des
paramètres.
y Si les types T1 et T2 définissent l’opérateur de
comparaison < alors pair<T1,T2> le définit aussi.
#include <iostream>
#include <utility>
Fichier en-tête contenant
La définition de pair
int main()
{
std::pair<int,double> p1(1,2.0), p2=std::make_pair(3,4e0);

std::cout << "p1=(" << p1.first << ","


<<p1.second << ")\n"
<< "p2=(" << p2.first << ","
<<p2.second << ")\n";
}
Limites
y Les classes numeric_limits<T> permettent de connaître les
caractéristiques de chaque type.
y Une liste assez complète de membres est disponible dont :
max(), min(), digits, digits10, is_signed, is_integer, etc.
y Tous les membres sont statiques
y Il faut inclure le fichier en-tête limits.

std::cout << "max(short) "


<< std::numeric_limits<short int>::max()
<< std::endl
<< "round to zero "
<< std::numeric_limits<double>::round_style
<< std::endl;
Fonctions auxiliaires
y Deux familles de fonctions auxiliaires sont disponibles
pour faciliter des tâches courantes.
y max, retourne le maximum de ses arguments, elle
s’applique à tout type qui peut être comparé, l’opérateur
doit être < défini.
y Swap, échange les valeurs de deux variables (passés par
référence), s’applique à tout type pouvant être copié.
#include <iostream>
#include <algorithm> Fichier en-tête contenant
La définition de max et swap
int main()
{

double a=1., b=-7.;


std::cout << "max(" << a << "," << b << ")="
<< std::max(a,b) << std::endl;

std::swap(a,b);
std::cout << "a=" << a << "\nb=" << b << std::endl;

}
Opérateurs de comparaison
y Le namespace std::rel_ops contient une famille
d’opérateurs génériques qui permettent de définir tous les
opérateurs de comparaison pour toute classe qui définit <
et ==.
y Pour utiliser rel_ops il suffit d’importer le namespace avec
l’instruction using.
#include <utility>
class X {

public:
bool operator== (const X& x) const;
bool operator<(const X& x) const;

};
void f()
{
using namespace std::rel_ops;
Les comparaisons supplémentaires X x1, x2;
deviennent accessibles …
if( x1 != x2)
Les opérateurs != et > …
non définis dans la if (x1 > x2)
classe X sont …
automatiquement crées }
Fichier en-tête C
y Tous les fichiers en-tête de la librairie standard C sont
accessibles en C++ avec un nom préfixé par « c » et sans
le suffixe « .h »
y Les foncions C ne sont pas dans le namespace std.
y Exemples: cmath, cstddef, cstdlib.

#include <iostream>
#include <cmath>

int main()
{
std::cout << "pi=" << M_PI << "\nsin(1)=" << sin(1.0) << std::endl;

}
Auto_ptr
y L’utilisation de pointeurs en C++ peut être source
d’erreurs.
y La famille de classes auto_ptr permet de gérer
automatiquement le cycle de vie d’un pointeur.
y On évite:
y Les fuites de mémoire (pointeurs non désaloués)
y Les problèmes liés aux exceptions.
y Un auto_ptr est initialisé avec un pointeur obtenu par new,
le destructeur de auto_ptr se charge de libérer la mémoire,
la gestion de mémoire devient automatique.
y Un pointeur géré par auto_ptr ne peut pas être partagé.
y Si on copie un auto_ptr la variable originale n’a plus le
contrôle de la mémoire.
y Un auto_ptr ne peut pas être utilisé comme membre d’un
conteneur (vector, list, etc.).
y Si on a besoin d’un pointeur intelligeant pouvant partager
la gestion de la mémoire entre différentes variables on doit
préférer un shared_ptr (actuellement membre de boost qui
est désormais dans la bibliothèque standard).
y Le constructeur d’un auto_ptr reçoit comme argument un
pointeur.
y La classe aut_ptr définit les opérateurs * et -> permettant
d’utiliser la même sémantique que pour un pointeur.
#include <iostream>
#include <memory> En-tête déclarant auto_ptr
int main()
{
std::auto_ptr<int> p(new int(55)); Création de auto_ptr à
partir de mémoire obtenue
std::cout << "p=" << p.get() << "\n*p=" << *p << std::endl; par new
*p=10;
On "\n*p="
std::cout << "p=" << p.get() << utilise un<<auto_ptr comme un
*p << get()
std::endl;
permet de récupérer le
} pointeur
pointeur vers la mémoire gérée
par le auto_ptr
Exceptions de la librairie
standard
y Les composantes de la librairie standard peuvent jeter des
exceptions.
y La librairie standard définit des classes qui représentent
ses exceptions.
y Toute exception jetée par une composante de la librairie
standard dérive de la classe std::exception.
y La classe exception contient un membre what() qui renvoi
un char* avec un message d’erreur.
bad_alloc

Domain_error
bad_cast
Invalid_argument
bad_typeid
Length_error
logic_error

exception Out_of_range

ios_base::faillure
Range_error
Runtime_error
Overflow_error

Bad_exception
Underflow_error
#include <iostream>
#include <exception>

int main()
{
int n;
std::cout << "Taille=";
std::cin >> n;
try {
int *p=new int[n];
}
catch (std::exception &e)
{
std::cout << "exception " << e.what() << std::endl;
}
return 0;
}
STL
y La Standard Template Library est une partie de la librairie
standard C++ comprenant trois parties :
y Conteneurs. Utilisés pour gérer des collections d’objets d’un
type donné.
y Itérateurs. Utilisés pour parcourir les éléments des
conteneurs, ils font abstraction du stockage et peuvent être
utilisés pour représenter des parties de conteneurs.
y Algorithmes. Utilisés pour traiter des éléments de
conteneurs. Les algorithmes ne manipulent pas directement
les conteneurs, ils doivent utiliser des itérateurs.
Conteneur
Ité
rat
eu
r

Algorithme Itérateur Conteneur

t eur
ra
Ité
Conteneur
Conteneurs
y Les conteneurs permettent de stocker de façon optimale
plusieurs objets de même type.
y Chaque conteneur est optimisé pour un usage spécifique.
y On peut classer les conteneurs en deux familles:
y Conteneurs séquenciels: vector, deque, list. Les éléments
sont stockés dans un ordre décidé par l’utilisateur (par
exemple l’ordre d’insertion)
y Conteneur associatifs: set, multiset, map et multimap. Les
éléments sont stockés triés selon un ordre associé au type
(en général <).
Opération communes à tous les conteneurs, si TC est un
conteneurs :
y TC c, crée un conteneur c vide
y TC c1(c2), crée un conteneur c1 de même type que c2 et
copie les éléments.
y TC c(beg,end), crée un conteneur á partir de deux
itérateurs et copie les valeurs de [beg,end).
y c.size(), retourne le nombre d’éléments dans le conteneur.
y c.empty(), retourne vrai si le conteneur est vide.
y c.max_size(), retourne le nombre maximal d’éléments
pouvant être contenus dans le conteneur.
y c1==c2, c1!=c2, c1<c2, c1>c2, c1<=c2, c1>=c2,
compare deux conteneurs (ordre lexicographique).
y c1=c2, copie tous les éléments de c2 dans c1.
y c1.swap(c2), swap(c1,c2), échange les éléments de c1
et c2.
y c.begin(), retourne un itérateur vers le premier élément de
c.
y c.end(), retourne un itérateur vers la position après le
dernier élément.
y c.rbegin(), retourne un itérateur inverse vers le dernier
élément.
y c.rend(), retourne un itérateur inverse vers la position
avant le premier élément.
y c.insert(pos,elem), insère une copie de elem.
y c.erase(beg,end), efface tous les éléments dans
l’intervalle [beg,end).
y c.clear(), efface tous les éléments du conteneur.
Vector
y La famille de classes vector est une représentation d’un
tableau dynamique et des opérations permettant de
manipuler les données y stockés.
y L’accès à un élément se fait en O(1).
y L’insertion à la fin se fait en O(1), sauf exception.
y L’insertion ailleurs que à la fin se fait en O(n)
y Un vecteur se comporte d’une façon proche d’un tableau,
avec une syntaxe plus riche.
y On crée un vector de taille n en appelant le constructeur à
un argument entier non signé n.
y On peut aussi créer un vector contenant n copies de la
valeur elem en appelant le constructeur à deux arguments
n et elem.
y On accède à l’élément i en utilisant l’opérateur [i], dans ce
cas on ne fait aucune vérification de i.
y La fonction at(i) accède à l’élément i et vérifie que i est
valable, une exception est jetée si i<0 où i>=n.
y La fonction push_back(elem) permet d’ajouter un élément
à la fin d’un vector qui se trouve agrandi.
y La fonction resize(n) permet de changer la taille d’un
vector.
Size et capacity

y La performance de l’ajout d’éléments en fin d’un vector


est due au fait que la classe garde une réserve d’espace en
fin de mémoire.
y Le nombre d’éléments contenus dans un vector est donné
par size().
y Le nombre total d’éléments que le vector peut contenir
sans avoir à redimensioner la mémoire est donné par
capacity().
y Le changement de capacity() se fait automatiquement, on
peut donc avoir une insertion qui prend beaucoup de
temps.
#include <iostream>
#include <vector>

int main()
{
std::vector<int> vi(100),vj;

for (int i=0; i<100; ++i)


{
vi[i]=100-i;
vj.push_back(i);
}

std::cout << "size(vi)=" << vi.size() << " capacity(vi)=" << vi.capacity()
<< "\nsize(vj)=" << vj.size() << " capacity(vj)=" << vj.capacity()
<< "\nvi[0]=" << vi[0] << " vi[99]=" << vi[99]
<< "\nvj[0]=" << vj[0] << " vj[99]=" << vj[99] << std::endl;


vi.resize(128);
for (int i=100; i<128; ++i)
vi[i]=100-i;

std::cout << "size(vi)=" << vi.size() << " capacity(vi)=" << vi.capacity()
<< "\nvi[128]=" << vi[128] << std::endl;

vi.reserve(1000);
std::cout << "capacity(vi)=" << vi.capacity() << std::endl;
return 0;

}
y Les fonctions insert(…) permettent d’insérer des éléments
à une position donnée.
y La fonction pop_back() détruit le dernier élément et
diminue la taille du vector
y Les fonctions erase déruisent une parties des éléments du
vector.
Deque
y Un deque est très similaire à un vector sauf qu’on y peut
facilement insérer des éléments au début et à la fin.
y L’interface de deque est très similaire à celle de vector,
avec les différences suivantes :
y Il n’y a pas de fonctions capacity() et reserve().
y Les fonctions push_front() et pop_front permettent de
facilement insérer et détruire des éléments au début du
conteneur.
#include <iostream>
#include <deque>

int main()
{
std::deque<int> v(100);

for (int i=0; i<100; ++i)


v[i]=100-i;
for (int i=0; i<50; ++i)
{
v.push_back(i);
v.push_front(i*i);
}
std::cout << "size(v)=" << v.size()
<< "\nv[0]=" << v[0] << " v[" << v.size()-1 << "]=" << v[v.size()-1]
<< std::endl;

return 0;
}
List
y Une liste est un conteneur qui organise les éléments dans
une liste doublement chainée.
y L’insertion dans une liste se fait en O(1), l’accès à un
élément en O(n).
y Il n’y a pas d’opérateur d’accès direct aux éléments d’une
liste, tout accès doit être séquentiel. Pas de fonction at()
où d’opérateur [].
y Il n’y a pas de taille pré allouée pour une liste, donc pas de
capacity() où resize().
y Les listes ont des membres spécifiques pour transférer des
éléments qui sont plus rapides que les algorithmes.
#include <iostream>
#include <list>
#include <vector>

void printList(const std::list<int>& l1, const std::list<int> &l2)


{
std::cout << "List 1: ";
for (std::list<int>::const_iterator pi=l1.begin(); pi!=l1.end(); ++pi)
std::cout << *pi << ",";
std::cout << std::endl;

std::cout << "List 2: ";


for (std::list<int>::const_iterator pi=l2.begin(); pi!=l2.end(); ++pi)
std::cout << *pi << ",";
std::cout << std::endl;
}
int main()
{
std::list<int> list1, list2;

for (int i=0; i<10; ++i)


{
list1.push_back(i);
list2.push_front(i);
}
printList(list1,list2);

list2.splice(find(list2.begin(),list2.end(),3),list1);
printList(list1,list2);

list1=list2;
list2.sort();
printList(list1,list2);
list2.unique();
printList(list1,list2);
return 0;
}
Set
y Un set<T> contient des éléments de type T triées
automatiquement. T doit définir un ordre, par défaut on
utilise l’opérateur < mais une autre fonction peut être
utilisée.
y La recherche d’un élément a une complexité O(log(n)).
y Set possède quelques opérations spécifiques à la recherche
dans le conteneur :
y count(elem) retourne le nombre d’éléments avec valeur
égale à elem.
y find(elem) retourne le premier élément avec valeur elem.
y lower_bound(elem), upper_bound(elem), retournene la
position du premier élément >= elem, resp. <= elem.
y Dans un set il y a pas de duplication.
y Les membres suivants permettent l’insertion d’éléments :
y c.insert(…), plusieurs surcharges d’une même fonction
permettant d’insérer à différents endroits.
y c.erase(…) permet de effacer un ou plusieurs éléments.
y c.clear() efface tout le contenu de la liste.
#include <iostream>
#include <set>
#include <string>

int main()
{
std::set<std::string> couleurs;

couleurs.insert("bleu");
couleurs.insert("rouge");
couleurs.insert("vert");
couleurs.insert("jaune");
couleurs.insert("bleu");

for (std::set<std::string>::const_iterator p=couleurs.begin();


p != couleurs.end();
++p)
std::cout << *p << ",";
std::cout << std::endl;
}
Multiset
y Un multiset est un set acceptant des duplications
d’éléments.
y Multiset utilise le même fichier en tête que set.
y Alors que count retourne 0 où 1 pour un set elle peut
retourner une valeur > 1 pour un multiset.
#include <iostream>
#include <set>
#include <string>

int main()
{
std::multiset<std::string> couleurs;

couleurs.insert("bleu"); couleurs.insert("rouge");
couleurs.insert("vert"); couleurs.insert("jaune");
couleurs.insert("bleu");

for (std::multiset<std::string>::const_iterator p=couleurs.begin();


p != couleurs.end();
++p)
std::cout << *p << ",";
std::cout << std::endl;

std::cout << "count(jaune)=" << couleurs.count("jaune")


<< "\ncount(bleu)=" << couleurs.count("bleu") << std::endl;
}
Map
y Un map<K,T> est un conteneur permettant de gérer des
paires de clés de type K et valeurs de type T. Il peut être
vu comme un dictionnaire.
y La classe K doit avoir un ordre de tri, par défaut on utilise
l’opérateur < mais on peut spécifier une autre fonction.
y Dans un map les clés sont uniques.
y La recherche d’une clé dans un map est de complexité
O(log(n)).
y Un map peut être utilisé comme un tableau associatif, on
utilise l’opérateur [] avec un indice de type K.
y Les opérations de recherche count(key), find(key),
lower_bound(key), upper_bound(key) et
equal_range(key) sont disponibles pour les map, elles sont
similaires aux opérations de même nom pour les set et
s’appliquent aux clès. Ces opérations retournent des
std::pair<K,T>.
y Les opérations insert(…) et erase(…) sont aussi présentes,
dans insert l’élement à insérer est représenté par une
std::pair<K,T>.
#include <iostream>
#include <map>

int main()
{
std::map<std::string,double> nombres;

nombres.insert(std::make_pair("pi",3.14159));
nombres.insert(std::make_pair("e",2.71828));

nombres["catalan"] = 0.9159655;

for (std::map<std::string,double>::const_iterator p=nombres.begin();


p != nombres.end();
++p)
std:: cout << "nombres[" << p->first << "]=" << p->second
<< std::endl;
}
Multimap
y Un multimap est un map acceptant des duplications de
clès.
y L’opérateur [] n’est pas défini pour un multimap.
y La famille de classes multimap est définie dans le même
fichier en-tête que map.
#include <iostream>
#include <map>

int main()
{
std::multimap<std::string,std::string> dico;

dico.insert(std::make_pair("pi",
"Le rapport entre le perimètre et le diamètre d'un cercle."));
dico.insert(std::make_pair("pi",
"La seizième lettre de l'alphabet grec."));
dico.insert(std::make_pair("e","La base des logarithmes naturels."));

for (std::multimap<std::string,std::string>::const_iterator p=dico.begin();


p != dico.end();
++p)
std:: cout << p->first << " : " << p->second
<< std::endl;
}
Itérateurs
y Un itérateur permet de faire abstraction d’un parcours sur
un conteneur.
y Les itérateurs miment la syntaxe des pointeurs qu’on peut
observer sur l’exemple suivant :
int N=100;
double *t=new double[N];
for (double *p=t; p != t+N; ++p)
*p=(*p)+1;

y Les itérateurs représentent des intervalles semi-ouverts à


droite.
y On peut classer les itérateurs en plusieurs catégories :

Itérateur Possibilités Types qui l’utilisent

Entrée (input) Lecture de l’élément istream


suivant
Sortie (output) Écriture de l’élément ostream, inserter
suivant
Forward Lecture et écriture de list, set, multiset, map,
l’élément suivant multimap

Bi directionel Lecture et écriture de vector


l’élément suivant et du
précédent
Accès direct Lecture et écriture d’un vector, deque, string,
élément quelconque array
y L’interface de chaque itérateur dépend de son type, plus un
type a de possibilités plus son interface est riche.
y Pour les itérateurs d’entrée :
Expression Action
*iter Accès en lecture à l’élément
du conteneur
iter->membre Accès en lecture au membre de
l’élément du conteneur
++iter Avance vers la position
suivante, retourne la nouvelle
position.
iter++ Avance vers la position
suivante, retourne l’ancienne
position.
iter1 == iter2 Comparaison (égalité)
iter1 != iter2 Comparaison (différent)
TYPE(iter) Constructeur par copie.
y Les itérateurs de sortie ont les opérations suivantes :

Expression Action
*iter = valeur Écrit dans l’élément auquel
l’itérateur fait référence
++iter Avance vers la position
suivante, retourne la nouvelle
position.
iter++ Avance vers la position
suivante, retourne l’ancienne
position.
TYPE(iter) Constructeur par copie.
y Les itérateurs forward sont une combinaison d’itérateurs
d’entrée et de sortie, ils ont les opérations suivantes :
Expression Action
*iter Accède à l’élément auquel
l’itérateur fait référence
iter->membre Accède au membre de
l’élément auquel l’itérateur fait
référence.
++iter Avance vers la position
suivante, retourne la nouvelle
position.
iter++ Avance vers la position
suivante, retourne l’ancienne
position.
iter1==iter2 Comparaison (égalité)

iter1!=iter2 Comparaison (différence)


Expression Action
TYPE() Constructeur par défaut.

TYPE(iter) Constructeur par copie.

iter1=iter2 Assignation
y Les itérateurs bi-directionels sont des itérateurs forward
avec les opérations supplémentaires :
Expression Action
--iter Recule vers la position
précédente, retourne la
nouvelle position.
iter-- Recule vers la position
précédente, retourne
l’ancienne position.
y Les itérateurs d’accès aléatoire sont des itérateurs bi-
directionels avec les opérations supplémentaires :

Expression Action
iter[n] Accès à l’élément avec index
n.
iter+=n Avance de n éléments (recule
si n négatif).
iter-=n Recule de n éléments (avance
si n négatif).
iter+n Retourne un itérateur vers le
prochain n-ième élément.
iter-n Retourne un itérateur vers le
précédent n-ième élément.
iter1-iter2 Distance entre iter1 et iter2.
iter1 < iter2 Vérifie si iter1 est avant iter2.
Expression Action
iter1 > iter2 Vérifie si iter1 est après iter2.

iter1 <= iter2 Vérifie si iter1 n’est pas avant


iter2.
iter1>=iter2 Vérifie si iter1 n’est pas après
iter2.
y Chaque conteneur définit plusieurs types d’itérateus comme
sous types, les deux plus utilisés sont :
y C<T>::iterator
y C<T>::const_iterator
y Tout conteneur STL définit deux membres retournant des
itérateurs permettent de le parcourir dans l’ordre de stockage
: begin() qui référence le premier élément et end() qui fait
référence à une position après le dernier élément.

c.begin() c.end()
Fonctions auxiliaires d’itérateurs
y Trois fonctions auxiliaires sont définies pour tout
itérateur, la complexité dépend du type d’itérateur :
y advance : permet d’avancer un itérateur de n positions.
O(1) pour les itérateurs d’accès aléatoire, O(n) sinon.
y distance : permet de calculer la distance entre deux
itérateurs atteignables. O(1) pour les itérateurs d’accès
aléatoire, O(n) sinon.
y iter_swap : échange les valeurs pointés par deux itérateurs.
Fonctionne même si les itérateurs ne sont pas du même type.
Itérateurs inversés
y Un itérateur inversé permet de parcourir un conteneur en
sens inverse de l’ordre de stockage.
y Chaque conteneur définit plusieurs types d’itérateus comme
sous types, les deux plus utilisés sont :
y C<T>::reverse_iterator
y C<T>::const_reverse_iterator
y Tout conteneur STL définit deus itérateur inversés
rbegin() et rend() qui pointent respectivement vers le
dernier élément et vers une position avant le premier
élément.
c.rend() c.rbegin()
#include <iostream>
#include <vector>
#include <cmath>

int main()
{
std::vector<double> v;

for (double x=1; x<10; ++x)


v.push_back(sqrt(x));

for (std::vector<double>::iterator p=v.begin();


p < v.end();
++p)
{
std::cout << *p << ", ";
if ( fabs(*p-2.0) < 0.0001)
*p=-10.00;
}
std::cout << std::endl;
for (std::vector<double>::reverse_iterator p=v.rbegin();
p < v.rend();
++p)
std::cout << *p << ", ";
std::cout << std::endl;

return 0;
}
Itérateurs d’insertion
y Un itérateur d’insertion est un adaptateur qui transforme
une assignation en insertion.
y Un itérateur d’insertion est un opérateur de sortie pour
lequel les opérations suivantes ont un comportement
spécial :
y operator* n’a aucun effet et retourne *this, ceci a pour
conséquence que *pos est équivalent à pos.
y operator= a pour effet d’insérer dans le conteneur, en
général les appels sont transformés vers push_back(),
push_front() où insert().
Classe Fonction appelée Syntaxe
back_insert_iterator push_back(valeur) back_inserter(cont)
front_insert_iterator push_front(valeur) front_inserter(cont)
insert_iterator insert(pos,valeur) inserter(cont,pos)

#include <iostream>
#include <list>
#include <algorithm>

void PRINT(const std::list<int> &v)


{
for (std::list<int>::const_iterator p=v.begin();
p!=v.end();
++p)
std::cout << *p << ", ";
std::cout << std::endl;
}
int main()
{
std::list<int> v;

std::back_insert_iterator<std::list<int> > iter(v);

*iter=1;
iter++;
*iter=2;
PRINT(v);

front_inserter(v) = 44;
std::list<int>::iterator p=v.begin();
p++;
p++;
inserter(v,p) =55;
PRINT(v);

return 0;
}
Foncteurs
y Certains algorithmes acceptent des fonctions comme
arguments de fonctions ou de templates.
y Une classe qui surcharge l’opérateur () peut être utilisée à
la place d’une fonction (comme argument d’une fonction
représentant un algorithme).
y Un certain nombre de fonctions simples sont prédéfinies
dans la bibliothèque standard.
y La bibliothèque standard fournit un certain nombre de
templates et utilitaires qui permettent de produire des
fonctions complexes à partir de fonctions simples.
void PRINT(double i)
{ int main()
std::cout << i << std::endl; {
} std::list<double> l;

class MyFunc for (int i=0; i<10; ++i)


{ l.push_back(i/10.0);
public:
explicit MyFunc(double a) : a_(a) { } std::cout << "List1\n";
void operator()(double &x) const std::for_each(l.begin(),l.end(),PRINT);
{ MyFunc asinx(1.0);
x= a_ * sin(x); std::for_each(l.begin(),l.end(),asinx);
} std::cout << "List1\n";
void setA(double a) std::for_each(l.begin(),l.end(),PRINT);
{ asinx.setA(2.0);
a_=a; std::for_each(l.begin(),l.end(),asinx);
} std::for_each(l.begin(),l.end(),PRINT);
private:
double a_; return 0;
}; }
Fonctions prédefinies :
Expression Action
negate<T>() -param

plus<T>() param1+param2
minus<T>() param1-param2
multiplies<T>() param1*param2
divides<T>() param1/param2
modulus<T>() param1%param2
equal_to<T>() param1==param2
not_equal_to<T>() param1!=param2
less<T>() param1<param2
greater<T>() param1>param2
less_equal<T>() param1<=param2
Expression Action
greater_equal<T>() param1>=param2

logical_not<T>() !param
logical_and<T>() param1 && param2
logical_or<T>() param1 || param2
Adaptateurs :
Expression Action
bind1st(op,valeur) op(valeur,param)

bind2nd(op,valeur) op(param,valeur)
not1(op) !op(param)
not2(op) !op(param1,param2)

y L’utilisation des adptateurs demande que l’object fonction


passé en argument définisse deux type : T::argument_type
et T::result_type.
y Si on utilise son propre type on peut le dériver des classes
std::unary_function où std::binary_function.
y Pour utiliser une fonction membre comme argument d’un
adaptateur on doit utiliser std::mem_fun_ref où std::mem_fun
si l’argument est un pointeur vers un objet.
y Pour utiliser une fonction globale comme argument d’un
adaptateur on doit utiliser l’adaptateur std::ptr_fun.
#include <iostream> int main()
#include <list> {
#include <algorithm> std::list<double> l;
#include <functional>
#include <cmath> for (int i=0; i<10; ++i)
#include "boost/bind.hpp" l.push_back(i/10.0);

void PRINT(double i) std::cout << "List\n";


{ std::for_each(l.begin(),l.end(),PRINT);
std::cout <<i << std::endl; std::transform(
} l.begin(),
l.end(),
l.begin(),
std::bind2nd(std::multiplies<double>(),2)
);
std::cout << "List\n";
std::for_each(l.begin(),l.end(),PRINT);

return 0;
}
y Les adaptateurs de la bibliothèque standard ont deux
limitations importantes :
y Bind marche uniquement avec des fonctions de deux
variables.
y On ne peut pas composer des fonctions
y La bibliothèque boost fournit une généralisation des
adaptateurs standard qui règle ces problèmes.
y Une seule fonction boost::bind qui traite directement jusqu’à
9 paramètres
y Elle utilise des macros appelées placeholders (_1, _2, …, _9)
pour marquer les places des paramètres.
std::bind2nd(std::multiplies<double>(),2)
Equivalent à :
boost::bind(std::multiplies<double>(),_1,2)
#include <iostream>
#include <list>
#include <algorithm>
#include <functional>
#include <cmath>
#include "boost/bind.hpp"

void PRINT(double i)
{
std::cout <<i << std::endl;
}
int main()
{
std::list<double> l;

for (int i=0; i<10; ++i)


l.push_back(i/10.0);

std::cout << "List\n";


std::for_each(l.begin(),l.end(),PRINT);
std::transform(
l.begin(),
l.end(),
l.begin(),
boost::bind(std::multiplies<double>(),boost::bind(sin,_1),2)
);
std::cout << "List\n";
std::for_each(l.begin(),l.end(),PRINT);

return 0;
}
Algorithmes
y Les algorithmes agissent sur des conteneurs à travers des
itérateurs, ont peut les classer en familles :
y Non modificatifs
y Modificatifs
y Effacement
y Changement d’ordre
y Tri
y Sur des données triés
y Numériques
y Quelques algorithmes ont des versions avec suffixes :
y _if, quand deux formes de l’algorithme ont le même nombre
de paramètres une acceptant une valeur et l’; autre une
fonction.
y _copy, quand un algorithme a une forme qui copie manipule
les éléments sur place et une autre qui les copie, par exemple,
reverse() inverse l’ordre des éléments et reverse_copy() copie
les éléments dans un autre intervalle en inversant l’ordre.
Algorithmes non modificatifs
Nom Action
for_each() Applique un opération à chaque élément
count() Retourne le nombre d’éléments
count_if() Retourne le nombre d’éléments vérifiant une condition
min_element() Retourne le plus petit élément
max_element() Retourne le plus grand élément
find() Cherche un élément
find_if() Cherche un élément vérifiant une condition
search_n() Recherche les n premiers éléments avec une propriété
search() Recherche la première occurrence d’un sous intervalle
find_end() Recherche la dernière occurrence d’un sous intervalle
find_first_of() Recherche le premier élément parmi une liste
adjacent_find() Recherche des éléments adjacents qui sont égaux
Nom Action
equal() Vérifie que deux intervalles sont égaux
mismatch() Retourne les premier s éléments différents de deux
séquences
lexicographical_compare() Retourne si un intervalle est lexicographiquement
inférieur à un autre.
Algorithmes modificatifs
Nom Action
for_each() Applique un opération à chaque élément
copy() Copie un intervalle à partir du début
copy_backward() Copie un intervalle à partir de la fin
transform() Modifie et copie, où combine les éléments de 2 intervalles

merge() Fusionne deux intervalles


swap_ranges() Échange les éléments de deux intervalles
fill() Remplace chaque élément avec une valeur
fill_n() Remplace n éléments avec une valeur
generate() Remplace chaque élément avec le résultat d’une opération

generate_n() Remplace n éléments avec le résultat d’une opération


Nom Action
replace() Remplace les éléments avec une certaine valeur par une
autre valeur
replace_if() Remplace les éléments qui vérifient un critère par d’autres
éléments
replace_copy() Remplace en copiant les éléments avec une certaine valeur
par une autre valeur
replace_copy_if() Remplace en copiant les éléments qui vérifient un critère par
d’autres éléments
Algorithmes d’effacement
Nom Action
remove() Efface les éléments avec une valeur donnée
remove_if() Efface les éléments qui vérifient un critère
remove_copy() Copie les éléments qui n’ont pas une valeur donnée
remove_copy_if() Copie les éléments qui ne vérifient pas un critère
unique() Efface les éléments dupliqués adjacents
unique_copy() Copie les éléments en effaçant les dupliqués
Algorithmes de changement d’ordre
Nom Action
reverse() Inverse l’ordres des éléments
reverse_copy() Copie les éléments en inverseant leur ordre
rotate() Applique une rotation sur l’ordre des éléments
rotate_copy() Copie les éléments en appliquant une rotation sur l’ordre
next_permutation() Permutte l’ordre des éléments
prev_permutation() Permutte l’ordre des éléments
random_shuffle() Échange les éléments selon un ordre aléatoire
partition() Change l’ordres des éléments de telle forme que ceux qui
vérifient un critère se trouvent au début
stable_partition() Comme partition() mais garantit la préservation de l’ordre
des éléments qui vérifient et qui ne vérifient pas le critère.
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>

int main()
{
std::list<int> l;
for (int i=1; i<=4; ++i)
l.push_back(i);

PRINT(l);

std::vector<int> v;
std::back_insert_iterator<std::vector<int> > iter(v);

std::reverse_copy(l.begin(),l.end(),iter);
PRINT(v);

return 0;
}
Algorithmes de tri
Nom Action
sort() Trie les éléments
stable_sort() Trie en préservant l’ordre des éléments égaux
partial_sort() Trie jusqu’à ce que les n premiers éléments soient bons
partial_sort_copy() Copie les éléments en les triant
nth_element() Tri partiel en garantissant que les éléments avnt une position
sont plus petits
partition() Change l’ordre en garantissant que les premiers éléments
satisfont un critère
stable_partition() Comme partition() mais garantit la position des éléments
égaux
make_heap() Transforme un intervalle en tas
push_heap() Ajoute un élément à un tas
pop_heap() Efface un élément d’un tas
sort_heap() Trie un tas
Algorithmes pour données triés
Nom Action
binary_search() Cherche une valeur
includes() Cherche un intervalle dans un autre intervalle
lower_bound() Cherche le premier élément <= à une valeur
upper_bound() Cherche le premier élément >= à une valeur
equal_range() Cherche l’intervalles des éléments = à une valeur
merge() Fusionne eux intervalles
set_union() Retourne l’union de deux intervalles
set_intersection() Retourne l’intersection de deux intervalles
set_difference Retourne la différence de deux intervalles
set_simetric_difference() Retourne la différence symétrique de deux intervalles
inplace_merge() Fusionne deux intervalles consécutifs
Algorithmes numériques
Nom Action
accumulate() Combine les éléments (somme, produit, etc).
inner_product() Combine les éléments de deux intervalles
adjacent_difference() Combine chaque élément avec son prédécesseur
partial_sum() Combine chaque élément avec tous ses prédécesseurs
Flots
y Les flots sont utilisés pour les entrées sorties.
y Avec les flots ont peut lire et écrire dans différents
dispositifs : fichiers, strings, etc.
y Les classes qui manipulent des fichiers sont :
y std::istream, pour lecture
y std::ostream, pour écriture
y std::isstream, pour lecture écriture
y Les classes qui manipulent des strings :
y istringstream, pour lecture d’une chaine de caractères
y ostringstream, pour écriture dans une chaine de caractères
y L’écriture dans un stream se fait à l’aide de l’opérateur <<
y La lecture d’une stream se fait à l’aide de l’opérateur >>
y Les opérateurs << et >> retournent une référence vers un
stream.
y On définit les opérateurs comme fonctions globales.
Strings
y La classe std::string représente les chaines de catractères.