FAQ C++Consultez toutes les FAQ
Nombre d'auteurs : 34, nombre de questions : 368, dernière mise à jour : 14 novembre 2021 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.
Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur ou si vous souhaitez devenir rédacteur, lisez ceci.
Sur ce, nous vous souhaitons une bonne lecture.
- 6.1. Conteneurs (8)
- 6.2. Algorithmes (3)
Le C++ possède une bibliothèque standard (on parle aussi de SL pour Standard Library) qui est composée, entre autre, d'une bibliothèque de flux, de la bibliothèque standard du C, de la gestion des exceptions…, et de la STL (Standard Template Library : bibliothèque de modèles standard). En fait, STL est une appellation historique communément acceptée et comprise. Dans la norme on ne parle que de SL.
Comme son nom l'indique cette bibliothèque utilise fortement les templates C++ et le concept de généricité. Elle définit ainsi de nombreux modèles de classes et de fonctions génériques parmi lesquelles les conteneurs (tableau, liste, pile, ensemble…) et les algorithmes (copie, tri, recherche…) les plus courants. Une particularité importante est son approche orientée itérateurs, ce qui permet par exemple d'utiliser ses algorithmes sur d'autres conteneurs que ceux qu'elle fournit.
L'un des avantages de la STL par rapport aux autres bibliothèques remplissant (plus ou moins) le même rôle est qu'elle est standard, et donc théoriquement portable (cependant les limites de certains compilateurs compliquent la chose). Un autre avantage important est son polymorphisme paramétrique qui assure un typage fort sans exigence syntaxique à l'utilisation, c'est-à-dire par exemple que l'on peut très simplement créer un tableau de ce que l'on veut sans devoir downcaster depuis un horrible type commun tel que void *.
Utiliser la STL permet donc d'augmenter de manière significative sa productivité en C++ en écrivant du code fiable, performant et portable.
Toute classe surchargeant l'opérateur d'appel de fonction operator() est qualifiée de classe foncteur (functor class). Les objets instanciés d'une telle classe sont appelés objets fonctionnels (function objects) ou foncteurs (functors). La STL utilise beaucoup ce concept pour personnaliser le comportement de ses classes/fonctions.
Notez qu'on peut tout à fait utiliser des pointeurs sur fonction au lieu de foncteurs (il suffit de pouvoir appliquer l'opérateur () à l'objet passé en paramètre), mais on préfèrera les foncteurs car ils offrent plus de performances et de flexibilité. En effet operator() peut être entièrement inliné, et on peut passer des paramètres au foncteur via son constructeur pour plus de souplesse.
Voici un exemple typique de foncteurs tiré de la question [Exemple] Comment trier une séquence selon un critère personnalisé ?
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | struct A { int Number; std::string String; }; // Définition du foncteur servant à trier nos objets selon le nombre struct SortByNumber { bool operator ()( const A & a1, const A & a2 ) const { return a1.Number < a2.Number; } }; // Définition du foncteur servant à trier nos objets selon la chaîne struct SortByString { bool operator ()( const A & a1, const A & a2 ) const { return a1.String < a2.String; } }; |
Les prédicats (predicate) sont un type particulier de foncteurs qui renvoient un booléen ou quelque chose de convertible en booléen ce qui les rend utilisables dans des expressions logiques. Il existe un certain nombre de prédicats prédéfinis dans la STL, en particulier en ce qui concerne les opérateurs logiques et arithmétiques élémentaires :
Code c++ : | Sélectionner tout |
1 2 3 4 5 | int a = 2; if ( std::greater<int>()( a, 1 ) ) { // ce test est vrai car a > 1 } |
Code c++ : | Sélectionner tout |
std::set< std::greater<int> > entiersTriesParOrdreDecroissant;
std::bind1st et std::bind2nd sont un type particulier de foncteurs appelés foncteurs réducteurs. Ils permettent de facilement créer un prédicat unaire (c.a.d acceptant un seul paramètre) à partir d'un prédicat binaire (en acceptant deux paramètres). Ceci est fait en figeant la valeur d'un des deux paramètres du prédicat binaire (c.a.d. à le remplacer par une valeur fixe).
Soit l'exemple suivant où le prédicat plus_grand_que_10 est créé afin de compter grâce à std::count_if le nombre de valeurs supérieures à 10 dans un conteneur :
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <iostream> #include <vector> #include <algorithm> // prédicat personnalisé permettant de tester si un // entier est strictement supérieur à 10 struct plus_grand_que_10 { bool operator ()( int N ) const { return N > 10; } }; int main() { std::vector<int> v; v.push_back( 0 ); v.push_back( 5 ); v.push_back( 10 ); v.push_back( 15 ); v.push_back( 20 ); // compter le nombre de valeurs > 10 int n = std::count_if( v.begin(), v.end(), plus_grand_que_10() ); // utilisation de notre prédicat std::cout << n << '\n'; // affiche 2 } |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 | struct plus_grand_que_10 { bool operator ()( int N ) const { return 10 < N; } }; |
bind1st permet de figer le premier argument d'un prédicat binaire.
bind2nd permet de figer le second argument d'un prédicat binaire.
Ils s'utilisent de cette manière :
Code c++ : | Sélectionner tout |
<bind>( <foncteur>, <valeur du paramètre à figer> );
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <iostream> #include <vector> #include <algorithm> #include <functional> int main() { std::vector<int> v; v.push_back( 0 ); v.push_back( 5 ); v.push_back( 10 ); v.push_back( 15 ); v.push_back( 20 ); // compter le nombre de valeurs > 10 // méthode 1 : utilisation de bind2nd pour // la création d'un prédicat x > 10 int n = std::count_if( v.begin(), v.end(), std::bind2nd( std::greater<int>(), 10 ) ); std::cout << n << '\n'; // affiche 2 // méthode 2 : utilisation de bind1st pour // la création d'un prédicat 10 < x n = std::count_if( v.begin(), v.end(), std::bind1st( std::less<int>(), 10 ) ); std::cout << n << '\n'; // affiche 2 } |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.