Linux France

S'abonner à flux Linux France
Mis à jour : il y a 2 heures 42 min

Faut-il continuer à apprendre le C++ ?

Vendredi 27 Juillet

Le C++ est langage qui a vu ses spécifications s’amonceler et se stratifier au cours des années. Il est encore très utilisé. Mais face à des concurrents comme Rust ou Go, quel est sa place dans un environnement qui évolue ?

Cette dépêche qui a nécessité beaucoup de discussions, aura, vous le verrez, une forme un peu particulière

    Sommaire Origine de cette dépêche

    La dépêche C++17, Genèse d'une version mineure a reçu 227 commentaires représentant un volume dix fois supérieur à la dépêche elle-même. Et ces commentaires, très souvent bien écrits, nourrissent des trolls bien velus !

    L'idée de créer cette dépêche vient de deux constats :

    1. L'énergie dépensée et les nombreuses heures consacrées à rédiger ces 227 commentaires est phénoménale ;
    2. Par contre, la lecture de tous ces commentaires est laborieuse.

    Avec le recul, nous aurions pu concentrer tout cet investissement dans une dépêche collaborative du style « Aujourd'hui, est-il pertinent de choisir le C++ pour une nouvelle application ? » afin de structurer et consolider tous les arguments dispersés au fil des commentaires.

    Objectif de cette dépêche

    Cette dépêche propose un sujet bien plus large « Faut-il continuer à apprendre le C++ ? ». Et de nombreux commentaires de qualité de la dépêche C++17, Genèse d'une version mineure méritent d'être copiés/améliorés/fusionnés ici. Malheureusement, ceux-ci sont rarement sous licence compatible CC-BY-SA-4.0.

    gbdivers proposition

    Faire un article synthétique sur cette question n'est pas simple. En effet, le choix d'un langage pour un projet dépend énormément du contexte, en particulier le domaine d'application et l'environnement technique existant. Dans les discussions sur le choix d'un langage, certains avanceront des critères, mais ceux-ci seront considérés par d'autres comme non pertinent.

    Même des critères « historiques » du C++ ne sont plus des arguments suffisants dans de nombreux projets. Par exemple, le C++ est souvent évoqué pour ses performances lorsque l'on veut créer un jeu vidéo. Mais de nos jours, avec la puissance disponible sur le moindre appareil et la qualité des moteurs de jeux, il n'est plus pertinent que tous ceux qui veulent travailler dans les jeux vidéo apprennent le C++.

    De même, si on prend un domaine dans lequel le C++ est généralement déconseillé, comme le développement web. Et cependant, de très grosses entreprises web comme Google ou Facebook utilisent le C++.

    Il convient donc de revenir dans un premier temps sur les critères à prendre en compte dans le choix d'un langage, puis de voir les qualités et défauts du C++ sur ces critères.

    Dialogue sur divers aspects des enjeux brulants de C++ en 2018

    La normalisation, un processus trop lent ? Et quid de la nouvelle norme ISO vs mise à jour d'un soft (compilo, VM, etc).

    Nicolas Boulay: Vu la base de code existante et vu le nombre de parties prenantes, une prise de décision est forcément lente, vu les enjeux par chacune des parties. De toutes façons, ce n'est pas vraiment la rapidité des changements de la norme qui sont impactant, c'est la vitesse de conformance des compilateurs.
    Si c'est lent, les fonctionnalités vont prendre du retard avec les langages comme C#, Rust,… surtout s’ils continuent à avancer. Si c'est rapide, il faut accompagner le changement, pour ne pas dérouter les codeurs. Il y a risque de ne pas utiliser les nouveautés par peur d'instabilité, d'immaturité du code, ou de méconnaissance.
    gbdivers: oui, je suis d'accord.
    À mon avis, c'est avec ce type d'arguments que l'article sera intéressant. Les lecteurs ne connaissent pas forcément le contexte et les contraintes du C++, donc c'est bien de donner le contexte, puis les avantages et défauts des choix possibles. Libre à eux ensuite de se faire leur propre opinion.
    Anthony J.: Les industriels
    Je pense que pour de nombreux industriels utilisant le C++ depuis plus de 20 ans, les besoins de rétrocompatibilité restent très importants.
    gbdivers: bonne question : ont-ils besoin de rétrocompatibilité sur les évolutions du C++, ou ont-ils simplement besoin de ne pas suivre les évolutions ? On a au moins deux choix possibles : le choix entre suivre les évolutions du langage et mettre à jour son code, ou ne pas mettre à jour son code et ne pas suivre les évolutions du langage. Faut-il avoir un troisième choix : suivre les évolutions et ne pas mettre à jour son code ? Est-ce que ce troisième choix est intéressant/pertinent pour les industriels ? Pour le C++ ?
    Un exemple concret, dans ma boîte, ils ont choisi il y a trois ou quatre ans de mettre à jour le code et de ne plus assurer la rétrocompatibilité. Et depuis, on est sur le C++11 (il n'est pas prévu que l'on passe au C++14 ou 17 pour le moment). Et on garantit la compatibilité du code sur une liste définie de compilateurs et de versions de compilateurs. C'était un choix stratégique à faire entre obliger nos clients à mettre à jour leur code (et donc potentiellement perdre des clients) ou continuer à assurer la compatibilité (avec les coûts de développement que cela implique).

    gbdivers: standard vs lib ? Pourquoi ne pas mettre toutes les fonctionnalités dans le standard. Exemple de regex, network, unicode.

    Nicolas Boulay: une uniformisation serait souhaitable
    gbdivers: Idem. Quels sont les avantages et défauts d'une uniformisation ? D'une standardisation ? D'une standardisation ISO ? Vaut-il mieux une fonctionnalité dans le standard ou dans une lib ? Quelles sont les conséquences de l'un ou l'autre choix ?
    Nicolas Boulay: L'uniformisation permet toutes les avantages de la standardisation. Si on parle de la lib standard, d'un point de vue utilisateur cela ne change rien.
    gbdivers: l'antithèse est que l'uniformisation peut figer (dans le sens péjoratif = bloquer les évolutions futures) une API ou des fonctionnalités. Prenons par exemple le protocole HTTP. Si le standard C++ fournit une API pour cela, il faut que l'API puisse suivre les évolutions. Sinon, s'il y a une mise à jour de HTTP, soit on continue à utiliser l'API pas a jour du C++, soit on utilise une API a jour fournie par une lib. Dans les 2 cas, c'est problématique de fournir une API figée dans le standard. Il faut que l'API soit indépendante de la version du protocole, de façon a ce que les compilateurs puissent fournir des mises a jour du protocole sans que le standard change.
    freem: il y a aussi le problème de la rétro compatibilité. Par exemple, admettons que l'on intègre (reproche régulièrement lu et entendu) une section pour créer des IHM graphiques. Ce que le développeur voudra, c'est un truc qui soit stable au niveau UX /et/ intégré dans les OS (windows, macOS, gtk, qt…). Vu que celles-ci évoluent au fil du temps, tant dans leurs API que dans leurs architectures, le risque d'avoir une partie du standard qui soit instable (au niveau API du moins) serait élevé.

    gbdivers: Les nouveaux langages sont-ils meilleur que les anciens langages ? De grands débats apparaissent : const vs mutable, ref vs copie, explicit vs implicit.

    Nicolas Boulay: il ne faut pas oublier l'apport de la recherche dans le domaine : le temps de dev directement lié aux nombres de ligne de code (o(L1.2 ), cf Cocomo). La liste des bugs les plus fréquents en C / C++ qui sont toujours les mêmes (NULL, off by one, buffer overflow, allocation/désallocation mémoire, mauvaise gestion d'erreur, etc.), et qui n'existent pas dans les langages plus récents.
    gbdivers:
    L'argument sur les avantages que peuvent apporter un nouveau langage est à rapprocher du coup au problème de rétro-compatibilité.
    je ne connais pas Cocomo.
    freem: Cocomo est une méthode qui consiste à chiffrer le coût d'un projet en fonction de son nombre de lignes de code. C'est… heu… pas très moderne (né en 1970) et de ce que j'en sais totalement bancal: en C++ il est possible d'utiliser de l'objet, l'encapsulation est très encouragée par les mécanismes (RAII, move semantic, généricité) et donc pour contribuer à un code C++ /idéal/, le coût peut être très faible malgré un grand nombre de lignes de code, tant que l'on sait dans quelle couche on se situe: par exemple, pour un bug de mémoire (segfault, overflow) il est peu pertinent d'attaquer le code haut niveau, qui peut représenter le plus gros (avec pleins de règles métier ajoutées au fil du temps). Personnellement, de ce que je sais, la complexité cyclomatique de Mc. Cabe me semble plus pertinente que le nombre de lignes pour estimer la complexité d'un code (je vous renvoie à l'outil cccc, présent dans toutes les bonnes distros) dont j'ai personnellement tiré pas mal de leçons. Le problème des under/overflow pourrait être contrecarré en encapsulant les types natifs dans des classes. Le problème, c'est que le coût à l'exécution serait non négligeable. Pour la constance, je rappelle que, par défaut, les paramètres d'une fonction en C++ sont invisibles par l'appelant: passage par copie, sauf si on passe une référence. Du coup, on choisit volontairement un type mutable (dont c'est le rôle). Quand on a besoin d'une référence constante, c'est en fait un workaround dû au fait que la copie est lente: ce qui est, d'ailleurs, bien moins vrai depuis 2011. Ici encore, comme pour les *flow errors, il serait possible d'implémenter une solution plus propre à base de pointeurs intelligents (weak_ptr dédié à unique_ptr, qui pourrait interdire l'altération de la variable cible).
    Ici, je dirais que les erreurs les plus communes du «C/C++» sont dues au fait que, en C++ on tendance à programmer comme en C, comme le montre si bien la fusion de tant de gens: «C/C++»…

    gbdivers: Peut-on envisager de casser la rétrocompatibilité ? Exemple du python2 vs python3 montre l'étendue des problèmes que cela implique…

    Nicolas Boulay: à ne surtout pas faire, cela revient à créer un nouveau langage (sauf à être compatible binaire, avec un flag dans le fichier, comme hhack de facebook)
    gbdivers: Idem, prise de position. Si on le fait, il y aura telles conséquences. Si on le fait pas, il y aura telles autres conséquences.
    Nicolas Boulay: avec un flag, vous gardez la rétrocompatibilité, et vous nettoyez en même temps le langage pour le futur. Si vous cassez la compatibilité, vous inventez un nouveau langage, il faut donc convaincre à migrer. Ce qui ne se fera pas. Pour migrer à un nouveau langage, il faut de sacrer bonne raison. C++n-1 sera toujours « good enough » pour beaucoup.
    gbdivers: pour le flg, je sais pas trop. Toujours est-il que je suis d'accord. Je pense que l'exemple de Python2 vs Python3 (et plus précisément la lenteur d'adoption de Python3) est un bon exemple concret que ne pas assurer la rétro-compatibilité du code peut ralentir l'adoption de la mise a jour.
    freem: compte tenu de la vitesse d'évolution du C++, si on commence à casser la compatibilité, les compétences et le code accumulés entre deux versions seront potentiellement perdus. Le coût de formation pour avoir un développeur C++ compétent est déjà élevé, si en plus il faut le réinvestir régulièrement juste sur une «lubie» du comité, on risque surtout de voir un retour du C, ce qui serait à mon humble avis une terrible régression (le C à bien moins de fonctionnalités tout en offrant des performances comparables et moins de sécurité).
    Pour parenthèse, l'obsolescence de auto_ptr à dû être faite dans la douleur et dans le constat que c'était de toute façon peu utilisé (il suffit serait intéressant de grepper auto_ptr dans la base de code des paquets Debian, par rapport au nombre de projets écrits en C++: je suis certain que c'est ultra-minoritaire. Personnellement, je n'ai souvenir que d'un seul projet qui l'ait utilisé, et je ne me souviens même plus du nom…). J'ai un peu plus de doutes sur l'obsolescence des bind1st/2nd, qui bien qu'horribles à utiliser ne me semblent pas avoir de raison liées à des bugs?

    gbdivers: complexe ? Oh oui ! Multiplication des syntaxes, syntaxes pas forcément intuitives

    Nicolas Boulay: nécessité d'un check des bonnes pratiques
    gbdivers: c'est un point auquel je n'avais pas pensé et qui serait intéressant d'aborder. Le C++ n'est pas simplement un langage, c'est un écosystème, qui doit être considéré dans son ensemble : compilateurs, libs, outils de vérifications, bonnes pratiques, apprentissage.
    freem: la compatibilité avec le C est l'un des arguments forts pour pousser le C++, et le support des syntaxes du C est nécessaire pour cela (je pense surtout aux casts). Ceci dit, les bons compilateurs sont capables de prévenir de ce genre de choses. Il est possible de migrer un code C, qui par défaut n'offre strictement aucun contrôle automatique de la bonne gestion d'une ressource partiellement au C++, ce qui réduit les temps, et les coûts, de migration de C vers C++ de façon drastique. Mais il est vrai qu'il n'existe que trop peu d'outils et de documentations claires (leur étant liés) favorisant la vérification automatique des bonnes pratiques, ou même, d'un simple coding style.
    ** On peut cependant regretter qu'il soit difficile de s'assurer que son code n'utilise pas par erreur une fonctionnalité que l'on a voulu bannir pour différentes raisons (les exceptions, les templates, la RTTI, etc).

    gbdivers: passage complexe entre langages

    freem: si on parle d'utiliser plusieurs langages dans un projet, justement, c'est bien plus simple en C++ qu'en C# ou Java: le langage commun utilisé étant le C, à priori, et le C++ étant compatible avec une grande partie du C, il n'y a pas besoin de définir des points d'entrées comme en Java. J'ai un très mauvais souvenir également de l'usage de C en C#, ou il faut concrètement lutter pour que le compilateur accepte de compiler du code «unsafe».
    en C++, il suffit d'encapsuler la ressource, ce qui est très simple dû à, je me répète, la RAII.
    en revanche, si on parle d'apprendre le C++ en venant d'un autre langage, c'est vrai que ce n'est pas trivial, surtout si on veut jouer avec les couches basses.

    gbdivers: L'apprentissage du C++ est réputé difficile…

    lmghs: J'imagine qu'on liste ici les 3 niveaux: historique (mémoire à la main, pays magique où les erreurs n'existent pas), 98-RAII (que je continue à appeler moderne, si si), 11-RAII (où l'on introduit les trucs orientés utilisateurs et pythonisants dès le début: auto, for-range-loop, lambdas pour algo standards…) .
    Là on rejoint la problématique de ce que l'industrie attend. Je suis encore en train de donner une formation cette semaine, et de savoir si les formés vont travailler sur un centos6, ou pire 5, ou un 7, guide ce que je peux leur enseigner pour répondre à leurs besoins immédiats. Ce qui ne m'empêche pas de faire du teasing, par contre dans un cas je vais parler d'auto_ptr et des boost::ptr_vector tandis que dans l'autre vector<unique_ptr<>> me suffit. Même problématique avec les projets en maintenance.
    Il y a aussi la question des publics entre un dev futur informaticien, un gars en embarqué, un scientifique, ou des gars en formation interne dans une SSII, les choix et possibilités ne sont pas toujours les mêmes.

    gbdivers: Conclusion : Est-ce que le C++ est fini ? Non !

    gbdivers: en fait, on peut même répondre à cette question (et a la question du titre) dès l'introduction. Pour directement mettre au clair les trolls : est-ce que quelqu'un pense que le C++ aura disparu dans 10 ans ? La réponse est non (même les trolls pourraient difficilement répondre oui a cette question. Même le COBOL est encore utilisé).

    Le C++ en bref

    Le C++ est un vieux langage (bientôt 40 ans) hérité du langage C avec lequel il entretient une compatibilité

    gbdivers: compatibilité de syntaxe, mais divergence dans la façon de concevoir les choses. Cela rejoint un des points donnés plus haut : le passage entre plusieurs langages. Quand un dev connait/utilise plusieurs langages, il ne maîtrise pas les spécificités de chaque concept dans chaque langage (un même concept peut avoir plusieurs interprétations proches, mais pas exactement identique).
    Par exemple pour le C vs C++, il y a des syntaxes communes, mais la façon de penser un code est complètement différente (gestion des ressources, des erreurs, etc). Cela a donc un coût de passer d'un langage à un autre.
    Anthony J.: La compatibilité de syntaxe n’est plus possible depuis déjà pas mal de temps : conversion pointeur -> void* Ok (c/c++) ; mais void* -> type* Ok(c)/Ko(c++), les tableaux de taille dynamique à l’exécution (C99).
    La fonction foo() => foo(…) en C mais foo(void) en C++.
    Un article sur le sujet ici.X
    gbdivers: je n'ai pas suivi le C11, si ces syntaxes sont encore valides ? A priori, le C++11 (ou 14?) est sense se base sur le C11, donc il est possible que ce ne soit pas compatible avec le C99. Mais dans ce cas, le C actuel n'est pas non plus compatible avec le C99.
    Du coup, au lieu de dire « il entretient une compatibilité », il faut préciser que la compatibilité syntaxique est limitée, et la compatibilité « conceptuelle » diverge complètement.
    freem: la compatibilité est limitée de facto par le fait que le C++ réserve plus de mots que le C. Un code en C peut par exemple très bien utiliser this, mais un tel code ne pourra pas compiler en C++ (mot réservé pour désigner l'instance de l'objet dont on appelle la méthode, le cas échéant). Il me semble qu'il existait d'autres points, mais je ne m'en souviens pas.

    De tout ce long historique, le C++ a évolué du mieux possible entre paradigmes de programmation et nouveaux besoins.
    Au final, sa syntaxe évolue lentement, est complexe, bourrée de subtilités et lente à compiler.

    gbdivers : aborder le problème de l'enseignement du C++ ? Le C++ est permissif, beaucoup de syntaxe pour faire la même chose. Beaucoup de cours essaient d'apprendre plusieurs syntaxes - en commençant par les plus obsolètes en général - sans donner de hiérarchie d'importance a l'apprenant. Résultat : complexité à comprendre et moins bonne maitrise en profondeur).
    freem: Au sujet de la lenteur de compilation, le problème est-il vraiment lié au langage, ou à l'implémentation de la STL et du compilateur? Je me rappelle très bien le jour ou j'ai découvert clang: la mémoire consommée par une compilation a été divisée par 2, et les temps de compilation du projet sur lequel je travaillais par 3. Je n'ai pas fait de tests de vitesse (moins besoin, meilleur matos) entre la STL de gcc et celle de clang, mais il est clair que ces derniers incluent beaucoup moins de fichiers, l'arborescence et les chaînes d'héritages sont bien moins complexes. J'ai vu au fil des années pas mal de messages sur le net indiquant que gcc compilait plus lentement que visual c++ aussi. Alors ce problème de lenteur, ne serait-il pas du, au final, à un problème de qualité de gcc (passage à enlever sauf si publication un trolldi hihi)? Concrètement, gcc utilisait un GC en C, et il y a quelques années (après ma découverte de clang en tout cas) ils ont parlé de réimplémenter certains passages en C++ justement pour réduire la nécessité de ce GC.

    Mais c'est aussi un langage permettant des optimisations de folie (costless abstraction).
    Le C++ est utilisé au quotidien, ne serait-ce que la plupart des environnements graphiques et des navigateurs web (pour flâner sur LinuxFr.org). Et le C++ continuera pour encore de nombreuses années à être utilisé en production, notamment pour les applications critiques.

    Le C++ n'est pas mourant. Au contraire, le C++ connait un vif intérêt depuis C++11.
    De plus en plus de personnes s'investissent à améliorer davantage ce langage, comme sur la vitesse de compilation qui devrait être grandement améliorée pour C++20.

    Alors, faut-il tout effacer et recommencer un nouveau langage qui par design prend en compte les contraintes de concurrence (multi-core, NUMA) et de montée en charge (scalability) ? Des langages de programmation tentent d'obtenir des performances similaires avec une syntaxe expressive et concise.

    freem: inventer un nouveau langage from scratch, ne serait-ce pas un peu comme reprendre un projet from scratch? On perd l'historique, ce qui peut être bien (plus simple de faire une meilleure architecture) et mal (on perd les correctifs de bugs).

    La puissance du C++

    Les points positifs qui démarquent le C++ sont sa programmation générique et sa méta-programmation qui permettent d'avoir des abstractions sans pénalité de performance. Mais aussi les possibilités de libération déterministe et implicite de n'importe quel type de ressource au travers du RAII si on le compare au C—les autres langages à exceptions disposent d'un Garbage Collector et suivent le dispose pattern pour les autres ressources, voire ils offrent des facilités équivalentes au RAII (try-with-resources en Java 7, using en C#, etc). Certains estiment que si on ne profite pas de ces fonctionnalités, mieux vaut utiliser un autre langage.

    freem: mais justement: les GC, ça pose des problèmes de performance que la RAII n'a pas. Par exemple, une connexion à une base de données en Java, si on ne la ferme pas manuellement, on risque de faire exploser la charge du SGBD tant qu'il ne passe pas pendant trop longtemps. On s'expose aussi à des ralentissements conséquents quand le GC passe s'il a beaucoup de travail à faire, choses qui auraient pu être faites à des moments moins critiques. Certaines ressources peuvent aussi se retrouver à manquer si l'on en alloue trop vite pour que le GC nettoie tout… bref, le GC à ses avantages (pas besoin de s'occuper de gérer les choses) mais implique de maîtriser l'outil sans quoi des problèmes différents arrivent.

    Les alternatives
    • C ;
    • Rust ;
    • Go ;
    • Dart ;
    • Elixir ;
    • Phoenix ;
    • Pony ;
    • D ;
    • Ocaml ;
    • Haskell ;
    • Ada ;

    Parmi ces langages, en excluant ceux qui ne sont qu'interprétés et ceux qui utilisent un garbage collector, les seuls qui pourraient remplacer C++ à performances égales sont donc C, Rust et D.

    gbdivers: pourquoi exclure les interprétés et les GC? Ça serait l'occasion de tordre le cou a un mauvais argument sur le C++ : les performances. On attend souvent "je veux faire des jeux vidéo, on m'a dit qu'il fallait faire en C++ pour les perfs. Alors qu'en pratique, les perfs ne sont pas critiques pour beaucoup d'applis. Et que les perfs dépendent aussi beaucoup de l'algorithme et structures de données. Il vaut mieux n'importe quel langage correctement utilise que le C++ mal utilisé)

    wilk Peut-être préciser ce qu'on entend par performance. Ce n'est pas la même chose au niveau d'une interface graphique, d'un serveur, d'un mobile, etc.

    khivapia: "Il vaut mieux n'importe quel langage correctement utilise que le C++ mal utilise" : argument valable pour tous les langages. Pour tirer le maximum de perfs de la machine physique, il ne faut pas de GC (il n'y en a pas de temps-réel et parallèle ; donc s'il se réveille au milieu du jeu d'action, paf, gros lag ! ) ni, bien sûr, de langage interprété (perte de perfs liées à la VM)
    gbdivers: je dis que "les performances du C++ ne sont pas forcement un critère pertinent", vous me répondiez "le C++ est plus performant". Ok. Mais cela ne change rien a mon argument.

    Pour détailler : écrire du code performant a un coût. Beaucoup n'ont pas le temps et les compétences pour mettre en place les méthodes permettant d'optimiser correctement le code. On peut écrire en C++ un code qui sera plus performant qu'un GC, mais on peut également écrire pire.
    Un exemple concret : http://0x80.pl/articles/simd-strfind.html Indéniablement, on peut avoir de meilleures performances si on sait tirer le meilleur de la machine. Mais combien sont capables de faire cela ? Et on a le temps de faire cela sur un vrai projet ? C'est dans ce sens la que je dis que les performances ne sont pas toujours un bon critère.
    Nicolas Boulay: Pour prendre un exemple, je serais faire ce genre d'optimisation. Mais seul C/C++ me donne accès aux fonctionnalités pour faire le travail. Avec les autres langages, c'est simplement hors de portée, ou beaucoup plus complexe (ASM ou appel de fonction externe).
    gbdivers: oui, mais tu reconnaitras sans problème je pense que tous ceux qui veulent faire du C++ n'ont pas forcement ces compétences. Ou le temps de faire correctement les choses dans un projet donné (deadlines).
    L'argument "faire du C++ pour les performances" n'est donc pas valide seul. Il faut regarder le contexte du projet, les moyens disponibles, les compétences, etc. C'est un problème que l'on voit souvent sur les forums, ou les débutants arrivent et disent "je veux faire un jeu, on m'a conseillé le C++ parce que c'est le plus performant". Alors qu'en pratique, avec un autre langage, ça ne sera pas moins performant (parce qu'ils ne sont pas capables d'aller chercher les performances du C++).
    freem: je suis d'accord avec gbdivers (je n'arrête pas de lire gdbivers grrr): je ne compte plus les push_back dans un vector dans une boucle de taille définie sans appel à réserver au préalable, et c'est bien moins complexe que le lien donné plus haut (pas encore lu, mais il est probable que je ne sache pas tout faire dedans). Je passerai également sur les vectors multiples de même nombre d'éléments utilisés ensemble (cache miss et appels à mallocs inutiles). Et ce sont les bases pour écrire un code rapide en C++.

    Nicolas Boulay -> tous les moteurs de jeux (unity3D, …) sont écrits en C++, par contre la logique des jeux eux-mêmes sont en javascript, en C#, en lua… En gros, cela demande moins d'effort de faire propre avec n'importe quoi d'autre que C++, sauf si les performances sont une absolue nécessité.

    Critères pour adopter un nouveau langage

    Mais pour qu'un langage soit adopté plusieurs ingrédients sont nécessaires :

    • Un gage de pérennité ;
    • Facile à débogage (déverminage) ;
    • Facile d'augmenter un programme ;
    • Une communauté, des meetups, des entreprises ;
    • Une galaxie de sites webs, d'outils divers, des bibliothèques, des tutoriels, de la documentation…
    • Des performances raisonnables.

    Sur ce terrain, le C++ est bien doté avec de très nombreux outils, bibliothèques et communautés.

    Popularité du C++

    Et toi, chère lectrice, cher lecteur, penses-tu que les nouvelles fonctionnalités du C++ ne font que compliquer inutilement le langage le plus complexe que l'humanité ait inventé ?
    Ou au contraire, es-tu persuadé.e que grâce à ces évolutions, le C++ va progresser dans le classement du TIOBE Index et garder loin derrière des prétendants comme D, Dart, Nim, Rust ou Pony ?

    Autres sources :

    Questions
    • Faut-il considérer le C++ comme langage potentiel au développement d'une nouvelle application ?
    • Est-il pertinent d'apprendre le C++ aujourd'hui ?
    Go

    Go a été créé par Google parce que la compilation C++ devenait rédhibitoire pour ses applications serveur.

    C++ a été initialement créé comme une extension du C, gardant la compatibilité avec lui, et non un pur langage objet. Il y a donc un mélange entre objet et types primitifs (comme dans java). Toutefois, contrairement à java ou C#, C++ ne fait pas de différences fondamentales entre les types primitifs et les objets définis par l’utilisateur : c’est au programmeur de décider si les types sont copiables, l’usage des références est explicite, l’allocation sur la pile est possible.

    Certaines briques « de base », telles que les conteneurs ou les string, sont toutefois arrivées tardivement dans la spécification, ou de manière incomplète. Ainsi, beaucoup de bibliothèques réinventent la roue, ce qui peut mener à des difficultés ou un surcoût (conversions multiples) dans l’interopérabilité entre bibliothèques.

    Le compilateur permet de faire de la vraie métaprogrammation. Et c'est réellement utilisé. La métaprogrammation en C++ repose sur un modèle de typage structurel.

    Par contre, il n'y a pratiquement aucune aide à la gestion d'erreur, bien que C++11 ait introduit static_assert. Les messages d’erreur liés à la métaprogrammation sont souvent particulièrement cryptiques et demandent un certain degré d’habitude ou d’expertise pour être compris, et un degré encore supérieur pour savoir écrire des bibliothèques fortement génériques provoquant des messages d'erreurs intelligibles. Voire à ce sujet la présentation de Roland Block donnée lors des CppCon 2015 : Pruning Error Messages From Your C++ Template Code (slides). À noter toutefois que les progrès récents du côté des compilateurs, tels que g++ ou clang++, font que les messages d'erreurs sont un peu moins longs qu'avant.

    La gestion de la mémoire, et des ressources en général, en C++ est laissée à la charge du développeur. Cela a pendant longtemps abouti à la multiplication des problèmes tels que fuites mémoires, use after free, qui se manifestent aujourd’hui en autant de failles de sécurité. Toutefois, C++ fournit maintenant des outils intégrés à la bibliothèque standard, qui suivent le principe de RAII (Ressource Acquisition Is Initialization) pour gérer finement l’utilisation des ressources. Ce principe a été repris et généralisé dans le langage Rust (créé par Mozilla), qui veut se poser en alternative, mais aujourd’hui reste inférieur en termes d’écosystème (SIMD, multicore / OpenMP, toolkit graphique façon Qt).

    D'un autre côté, si C++ trouve un moyen de détecter les vieilles constructions à éviter, que les types sommes et le pattern matching de type est ajouté, que les pointeurs soient vu comme des types sommes avec détection des "call sur null" à la compilation, si des conteneurs sont introduits avec des interfaces fold/map/reduce pour réduire les erreurs off-by-one lors des parcours, si la compilation est plus rapide (peut être avec une gestion multi-fichier du compilateur), si le modèle mémoire devient plus précis pour gérer les alignements mémoire, l'appartenance des objets en mémoire pour chaque thread, et pour un éventuel garbage collector, C++ est là pour longtemps.

    Les spécifications

    (Tiré du commentaire : https://linuxfr.org/news/c-17-genese-d-une-version-mineure#comment-1676200)

    La volonté de compatibilité des différentes versions de la norme pousse le comité de standardisation à ajouter des parties plutôt qu'à les remplacer. Cela pose plusieurs problèmes :

    • il est possible de voir différentes strates d'un mécanisme dans la spec et il n'existe pas vraiment d'outils pour savoir ce qui est bien ou pas ;
    • le maintien des programmes existant pour être compliqué pour se conformer à la nouvelle bonne pratique ;
    • les différentes bibliothèques utilisées ne sont pas forcément toutes homogène et peuvent contraindre à utiliser toutes les parties de la spec.

    En outre le comité de normalisation est fermé. Même si le langage est ouvert (son implémentation), les spécifications sont payantes et soumises à des droits. Une aberration qui entraîne parfois des soupçons de corruption ou du moins une volonté d'entretenir une complexité spéciale pour justifier des experts. Ces critiques sont toutefois largement injustifiées, les brouillons des spécifications (quasiment identiques à la version finale) étant en accès libre, et le comité de normalisation s’étant énormément ouvert à la communauté C++ depuis le début des années 2010.

    La bibliothèque standard pas homogène

    (Tiré du commentaire : https://linuxfr.org/news/c-17-genese-d-une-version-mineure#comment-1676200)

    La bibliothèque standard est très poussée pour des domaines assez pointus (comme les mathématiques), mais ne propose rien pour des usages très courant comme le multitâche qui est, lui, géré nativement par Rust.

    lmghs [Réponse au commentaire—brouillon à retravailler]> La situation a évolué depuis le C++11 qui a introduit mutex et autre locks, des threads, et des mécanismes pour l'asynchrone. L'asynchrone était assez imparfait et des efforts continus ont été investis dessus au point que les évolutions les plus visibles pour le C++17 concernent les aspects de la concurrence et du parallélisme. On observe une synergie importante avec la bibliothèque open-source HPX

    nicolas> la méthode lock/thread est une méthode qui engendre un paquet d'erreur (race condition, priority inversion, dead lock, …) , un cerveau humain normal a trop de mal avec ces paradigmes. Ce qui semble marcher est le message passing (Erlang, Qt, …), surtout si on sait faire du "zéro copy" (linear programming).

    Des problèmes quotidiens semblent compliqués

    (Tiré du commentaire : https://linuxfr.org/news/c-17-genese-d-une-version-mineure#comment-1676523)

    Des problèmes tout à fait quotidiens (comme le fait de n'inclure qu'une seule fois chaque fichier à la compilation) n'a pas de solution triviale. Chaque développeur/ou chaque projet gère du coup cela à sa façon avec potentiellement des erreurs et sans capitalisation au sein de la communauté C++.

    La gestion de dépendance / portabilité / build / reproductibilité

    Note de modération : paragraphe à travailler, je jette des idées en vrac

    La gestion de dépendance en C++ est complexe. il faut pouvoir compiler un logiciel dans un contexte reproductible, qui, dans le meilleur des cas :

    • est indépendant de la machine de compilation et de la machine cible ;
    • garantie que les bibliothèques utilisées seront toujours les mêmes (même numéros de version, même paramètre de compilation) ;
    • que le compilateur utilisé est le même ;
    • que tout cela est portable sur plusieurs systèmes ;
    • que le programme (binaire, répertoire de source, …) livrée peut être livré facilement sur une machine cible non maîtrisé. En gros, qu'ils viennent avec ses dépendances.

    Ce type de problème est souvent géré dans d'autre langages par des outils de gestion de dépendances, comme en python avec Pip_(package_manager), Haskell avec Stack_(software), etc. Ces outils permettent de construire son programme dans un environnement restreint en fournissant toute ou parties des garanties listées au-dessus.

    À ma connaissance, il n'existe pas d'outil multi-plateforme de ce type en C++, ainsi chaque bibliothèque vient avec sa propre méthode de compilation / installation non générique et le packaging d'un programme revient souvent à faire soi-même, à la main, le build de toutes les dépendances dans un répertoire dédié du projet, ce qui devient fastidieux quand on cherche aussi à s'assurer du numéro de version des outils de compilation utilisées.

    lmghs -> Il existe conan.io qui veut fédérer les choses, et Nuget sous windows. A voir où cela va nous mener.

    Sous windows, il n'y a rien de vraiment solide, chaque année voit son lot de gestionnaire de packet, comme Chocolatey, mais rien de suffisamment robuste / exhaustif permettant de choisir les versions exactes des bibliothèques / outils.

    Sous linux, chaque distribution propose son gestionnaire de packet, garantissant que les dépendances fonctionnent au sein du système. Cependant si la version de bibliothèque fournie ne correspond pas à celle nécessaire au programme, on en revient à une gestion à la main.

    On peut aussi utiliser une technologie de conteneur légers comme Docker et installer une distribution linux spécifique avec un ensemble de packets choisis, mais cette méthode pose le problème des performances, or une des raisons de l'utilisation de C++ étant les performances, on peut se retrouver bloqué. (*Citation / link needed)

    freem: je ne comprends plus la… on parle de construire l'application (build, compilation, linking?) ou de l'exécuter? Qu'il n'existe pas de gestionnaire de dépendances binaires est au contraire une bonne chose pour moi: c'est le boulot de l'OS ça. Enfin, de la distribution autour de l'OS.
    Si le problème c'est de détecter les dépendances et de compiler en fonction, alors je trouve que cmake est un très bon candidat, malgré un certain nombre de défauts (il semblerait que ce ne soit pas nickel niveau portabilité, bien que les textes que j'ai lu dans ce sens n'ont pas vraiment argumenté. Il y a aussi le fait que le système de build ne puisse être promené d'un dossier à l'autre (usage de chemins absolus dans le makefile généré)).

    Avantages du C++ sur les autres langages

    Le C++ a malgré tout des avantages que l'on ne retrouve dans aucun autres ou pratiquement :

    • Une manipulation bas niveau voir très bas niveau (du fait de sa proximité avec le langage C aujourd'hui majoritairement utilisée dans les microcontrôleurs à la place de l'assembleur) qui permet des optimisations très fines (On peut même y intégrer de l'assembleur). Il tient cette puissance de sa très forte proximité dans son fonctionnement avec l'ordinateur (au moins son Architecture de von Neumann, les machines actuelles ont seulement l'apparence de machine de von Neumann, mais si on veut des performances, il faut aller plus loin).
    • Il a évolué plus que tout autres langages en restant extrêmement rétro-compatible. Cela lui apporte :
      • un gage de stabilité (le code a de forte chance de compiler avec la prochaine version de C++) qui rassure les responsables logiciels.
      • Une capacité haut niveau tout en restant extrêmement performant qui n'a pas d'équivalent. C'est ce que lui envient entre autre le Go ou le Rust.
    • Les Système_d'exploitation étant écrits en C/C++ il est le langage pour parler nativement au système et donc efficacement. Profitant de ces avantages, de nombreuses bibliothèques système ou bas niveau sont aussi en C:/C++.
    • L’écosystème C++ est riche de nombreuses bibliothèques inévitables dans certains domaines. Par exemple, de nombreux formats de fichiers et utilitaires de l'industrie du cinéma, tel que OpenEXR, OpenFX, OpenColorIO, OpenImageIO, Alembic, OpenVDB, [OpenEXRID] https://github.com/MercenariesEngineering/openexrid), etc., sont fournis sous la forme de bibliothèques C++. Bien que des Bindings vers d'autres langages existent, ceux-ci ne garantissent pas forcement une compatibilité parfaite aussi bien en termes de fonctionnalités que de performances. Par exemple, un tableau dynamique C++ (std::vector) n'est pas forcement compatible au niveau binaire avec son équivalent Rust, imposant la création d'une interface.
    Note aux lecteurs-commentateurs

    Je donne des exemples de bibliothèques de cette industrie parce que c'est celle que je connais et c'est actuellement la seule raison qui justifie notre utilisation du C++, d'autre personnes sont invitées à ajouter des exemples venant d'autres industrie. De façon amusante, on dit souvent que des langages comme python servent à faire la glue sur les entrées d'un programme et que le cœur est écris dans un langage plus "sérieux" type C++. Nous on aurait plutôt tendance à vouloir utiliser du Rust / Haskell pour le cœur et à utiliser C++ pour la glue et les entrées / sorties. C'est un point de vue assez amusant et à contre courant des idées habituelles.

    Et c'est ce point sur les performances tout en étant relativement haut niveau qui font du C++ un langage que l'on ne peut remplacer dans beaucoup de projets. Les seuls candidats sont des langages aussi très anciens et qui finalement ont moins évolué (Pascal, Fortran…)
    Bien souvent on développe une application dans un langage haut niveau (Python, PHP, Ruby ou autre). Puis viens un moment ou pour des raisons de performance on doit réécrire les parties les plus sollicitées. Par exemple dans notre société on développe en PHP et AWK. Et quand les charges serveurs augmentent, on réimplémente le cœur en C/C++ et on garde une couche Bash / PHP au-dessus. La raison pour laquelle on ne développe pas directement en C/C++, est que son développement et sa maintenance sont plus longues. En C/C++ un bug peut survenir sur un détail difficile à identifier là ou le PHP très tolérant accepte les problèmes. Il y a aussi en C/C++ le risque de ne plus savoir quelle version exacte du code avait servi à compiler la précédente version et donc une difficulté à savoir si lors d'une mise a jour les dernières évolutions du code ne vont pas perturber le fonctionnement en place. Autrement dit, il est difficile de savoir entre 2 exécutables quelles sont les modifications apportées.

    Le C++ fait aussi son apparition dans l'embarqué. Là où il n'y avait qu'assembleur et C, la suite logique pour des composants toujours plus complexe est le C++. D'abord à travers l'utilisation simple de classes, permettant une meilleure architecture soit par encapsulation soit par héritage. Mais de plus en plus, on voit arriver des morceaux de la bibliothèque standard, au fur et à mesure que l'embarqué accepte l'allocation dynamique de mémoire.

    Une autre force du C++ est la base d'utilisateur le connaissant du fait de sa longévité — il date de 1983.

    Télécharger ce contenu au format Epub

    Commentaires : voir le flux atom ouvrir dans le navigateur

    Pages