Académique Documents
Professionnel Documents
Culture Documents
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
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
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
int main()
{
std::vector<int> vi(100),vj;
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);
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>
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");
int main()
{
std::multiset<std::string> couleurs;
couleurs.insert("bleu"); couleurs.insert("rouge");
couleurs.insert("vert"); couleurs.insert("jaune");
couleurs.insert("bleu");
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;
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."));
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 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.
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;
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>
*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;
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)
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;
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
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.