C ++ Russie: comment c'était

Si au début de la pièce vous dites que le code C ++ est accroché au mur, alors à la fin il devrait certainement vous tirer dans le pied.

Bjarne Stroustrup

Du 31 octobre au 1er novembre, Saint-Pétersbourg a accueilli la conférence C ++ Russia Piter, l'une des plus grandes conférences de programmation en Russie organisée par le groupe JUG Ru. Parmi les conférenciers invités figurent des membres du comité de normalisation C ++, des conférenciers de CppCon, des auteurs de livres de O'Reilly, ainsi que des responsables de projets tels que LLVM, libc ++ et Boost. La conférence s'adresse aux développeurs C ++ expérimentés qui souhaitent approfondir leur expertise et échanger leurs expériences en communication en direct. Les étudiants, étudiants diplômés et professeurs d'université bénéficient de remises très agréables.

L'édition de Moscou de la conférence peut être visitée dès avril de l'année prochaine, mais pour l'instant nos étudiants vous diront quelles choses intéressantes ils ont apprises lors du dernier événement.



Photo de l'album de la conférence

À propos de nous


Deux étudiants de l'École supérieure d'économie de Saint-Pétersbourg ont travaillé sur ce poste:

  • Lisa Vasilenko est une étudiante de premier cycle de 4e année qui étudie la direction des «langages de programmation» dans le cadre du programme «Mathématiques appliquées et informatique». Connaissant le langage C ++ en première année d'université, il a par la suite acquis une expérience de travail avec lui lors de stages dans l'industrie. La passion des langages de programmation en général et de la programmation fonctionnelle en particulier a marqué le choix des rapports lors de la conférence.
  • Danya Smirnov est une étudiante de première année du programme de maîtrise «Programmation et analyse des données». Alors qu'il était encore à l'école, il a écrit les problèmes de l'Olympiade en C ++, puis il est arrivé que le langage apparaissait constamment dans les activités éducatives et devenait par conséquent le principal outil de travail. J'ai décidé de participer à la conférence afin d'enrichir mes connaissances et de découvrir de nouvelles opportunités.

Dans le bulletin d'information, les professeurs partagent souvent des informations sur les événements éducatifs liés à notre spécialité. En septembre, nous avons vu des informations sur C ++ Russia et avons décidé de nous inscrire comme auditeurs. Il s'agit de notre première expérience de participation à de telles conférences.

Structure de la conférence


  • Rapports


Au cours de deux jours, les experts ont lu 30 rapports mettant en évidence de nombreux sujets d'actualité: applications pleines d'esprit des fonctionnalités du langage pour résoudre les problèmes appliqués, mises à jour linguistiques à venir en raison de la nouvelle norme, compromis dans la conception C ++ et précautions lors de l'utilisation de leurs conséquences, exemples d'architecture de projet intéressante, ainsi que certaines parties du moteur de l'infrastructure linguistique. Dans le même temps, 3 représentations ont eu lieu, le plus souvent deux en russe et une en anglais.

  • Zones de discussion


Après le discours, toutes les questions sans réponse et les discussions incomplètes ont été transférées dans des zones de communication spécialement désignées avec des conférenciers équipés de panneaux de signalisation. Un bon moyen de passer la pause entre les performances pour une conversation agréable.

  • Lightning Talks et discussions informelles


Si vous souhaitez rédiger un court rapport, vous pouvez vous inscrire à une soirée Lightning Talk sur un tableau indicateur et disposer de cinq minutes pour parler de tout ce qui concerne le sujet de la conférence. Par exemple, une introduction rapide aux désinfectants pour C ++ (qui s'est avéré être nouveau pour certains) ou une histoire sur un bug dans la génération d'une sinusoïde que vous pouvez seulement entendre mais pas voir.

Un autre format est la table ronde «Avec le comité de l'âme». Sur la scène, il y a des membres du comité de normalisation, sur le projecteur - une cheminée (officiellement - pour créer une atmosphère émouvante, mais la raison «parce que tout est en feu» semble plus drôle), des questions - sur la vision standard et générale du C ++, sans discussions techniques passionnées et holivars. Il s'est avéré que des personnes vivantes siègent également au comité, qui ne sont peut-être pas complètement sûres de quelque chose ou peuvent ne pas savoir quelque chose.

Pour les passionnés d'Holivar, le troisième événement est resté: la session BOF «Go Again C ++». Nous prenons un amoureux de Go, un amoureux de C ++, avant le début de la session, ils préparent ensemble 100500 diapositives sur le sujet (comme des problèmes avec les packages en C ++ ou le manque de génériques en Go), puis ils discutent avec eux-mêmes et le public, et le public essaie de comprendre deux points de vue à la fois . Si l'holivar ne démarre pas, le modérateur intervient et réconcilie les parties. Ce format crée une dépendance: quelques heures après le début, seulement la moitié des diapositives ont été achevées. La fin a dû être fortement accélérée.

  • Stands partenaires


Les partenaires de la conférence étaient représentés dans les halls - ils ont parlé des projets en cours sur les stands, proposé des stages et des emplois, organisé des quiz et de petits concours, et ont également joué de beaux prix. Cependant, certaines entreprises ont même proposé de passer par les premières étapes des entretiens, ce qui peut être utile pour ceux qui ne sont pas seulement venus écouter les reportages.

Détails techniques des rapports


Nous avons écouté les rapports les deux jours. Parfois, il était difficile de choisir un rapport parmi ceux qui fonctionnaient en parallèle - nous avons convenu de partager et d'échanger les connaissances acquises pendant les pauses. Et même ainsi, il semble que beaucoup a été perdu. Ici, nous aimerions parler du contenu de certains rapports qui nous ont semblé les plus intéressants

Exceptions en C ++ à travers le prisme des optimisations du compilateur, Roman Rusyaev




Diapositive de présentation

Comme son nom l'indique, Roman a envisagé de travailler avec des exceptions en utilisant le LLVM comme exemple. Dans le même temps, pour ceux qui n'utilisent pas Clang dans leur travail, le rapport peut toujours donner une idée de la façon dont le code peut potentiellement être optimisé. En effet, les développeurs de compilateurs et des bibliothèques standard correspondantes communiquent entre eux et de nombreuses solutions réussies peuvent coïncider.

Ainsi, pour gérer l'exception, vous devez effectuer de nombreuses actions: appeler le code de traitement (le cas échéant) ou libérer des ressources au niveau actuel et dérouler la pile plus haut. Tout cela conduit au fait que le compilateur ajoute des instructions supplémentaires pour potentiellement lancer des appels. Par conséquent, si une exception n'est en fait pas provoquée, le programme commencera toujours à effectuer des actions inutiles. Afin de réduire en quelque sorte les frais généraux, LLVM a plusieurs heuristiques pour déterminer les situations où vous n'avez pas besoin d'ajouter un code de gestion des exceptions ou vous pouvez réduire le nombre d'instructions "inutiles".

L'orateur en examine une dizaine et montre à la fois les situations où elles permettent d'accélérer l'exécution du programme, et celles où ces méthodes ne sont pas applicables.

Ainsi, Roman Rusyaev conduit l'auditoire à la conclusion que le code contenant du travail avec des exceptions ne peut en aucun cas toujours être exécuté avec une surcharge zéro, et donne les conseils suivants:

  • lors du développement de bibliothèques, vous devez abandonner les exceptions en principe;
  • si vous avez encore besoin d'exceptions, dans la mesure du possible, cela vaut la peine d'ajouter des modificateurs noexcept (et const) afin que le compilateur optimise autant que possible.

De manière générale, l'orateur a réitéré le point de vue selon lequel il vaut mieux utiliser les exceptions au minimum, voire les abandonner.

Les diapositives du rapport sont disponibles sur: [«Exceptions C ++ via le prisme de l'optimisation du compilateur LLVM»]

Générateurs, coroutines et autres douceurs cérébrales, Adi Shavit



Diapositive de présentation

L'un des nombreux rapports de cette conférence consacrée aux innovations du C ++ 20 a été retenu non seulement par sa présentation colorée, mais aussi par sa désignation claire des problèmes avec la logique de traitement de la collection (pour, boucle de rappel).

Adi Shavit souligne les points suivants: les méthodes actuellement disponibles parcourent toute la collection et ne donnent pas accès à un état intermédiaire interne (ou donnent dans le cas des rappels, mais avec beaucoup d'effets secondaires désagréables, comme le même Callback Hell). Il semblerait qu'il y ait des itérateurs, mais tout ne va pas si bien avec eux: il n'y a pas de points d'entrée et de sortie communs (début → fin versus rbegin → rend et ainsi de suite), on ne sait pas combien allons-nous répéter? À partir de C ++ 20, ces problèmes sont résolus!

La première option: les plages. En raison du wrapper au-dessus des itérateurs, nous obtenons une interface commune pour le début et la fin de l'itération, ainsi que la possibilité de composition. Tout cela facilite la construction de pipelines de traitement de données à part entière. Mais tout n'est pas si fluide: une partie de la logique des calculs se trouve à l'intérieur de l'implémentation d'un itérateur spécifique, ce qui peut compliquer le code de perception et de débogage.


Diapositive de présentation

Eh bien, dans ce cas, des coroutines ont été ajoutées en C ++ 20 (fonctions dont le comportement est similaire aux générateurs en Python): l'exécution peut être retardée en renvoyant une valeur courante tout en conservant un état intermédiaire. Ainsi, nous réalisons non seulement le travail avec les données telles qu'elles apparaissent, mais nous encapsulons également toute la logique à l'intérieur d'une coroutine particulière.

Mais il y a une mouche dans la pommade: pour le moment, ils ne sont que partiellement pris en charge par les compilateurs existants, et ils ne sont pas non plus implémentés aussi précisément que nous le souhaiterions: par exemple, les liens et les objets temporaires ne devraient pas être utilisés dans les coroutines. De plus, il existe certaines restrictions sur ce qui peut être des coroutines, et les fonctions constexpr, les constructeurs / destructeurs et les principaux ne sont pas inclus dans cette liste.

Ainsi, les coroutines résolvent une partie importante des problèmes de simplicité de la logique de traitement des données, mais leurs implémentations actuelles nécessitent un raffinement.

Matériaux:


Astuces C ++ de Yandex.Taxi, Anton Polukhin


Dans son activité professionnelle, il faut parfois implémenter des choses purement auxiliaires: un wrapper entre l'interface interne et l'API d'une bibliothèque, la journalisation ou l'analyse. Cependant, il n'y a généralement pas besoin d'optimisation supplémentaire. Mais que faire si ces composants sont utilisés dans certains des services les plus populaires de Runet? Dans une telle situation, vous devrez traiter des téraoctets par heure de journaux seuls! Ensuite, chaque milliseconde compte et vous devez donc recourir à diverses astuces - Anton Polukhin en a parlé.

L'exemple le plus intéressant est peut-être l'implémentation du modèle pointeur vers implémentation (pimpl).

#include <third_party/json.hpp> //PROBLEMS! struct Value { Value() = default; Value(Value&& other) = default; Value& operator=(Value&& other) = default; ~Value() = default; std::size_t Size() const { return data_.size(); } private: third_party::Json data_; }; 

Dans cet exemple, vous voulez d'abord vous débarrasser des fichiers d'en-tête des bibliothèques externes - il se compilera plus rapidement et vous pourrez vous protéger contre d'éventuels conflits de noms et d'autres erreurs similaires.

Ok, déplacé #include dans le fichier .cpp: vous avez besoin de la déclaration directe de l'API encapsulée, ainsi que de std :: unique_ptr. Nous avons maintenant des allocations dynamiques et d'autres choses désagréables, comme des données dispersées sur un tas et des garanties réduites. Avec tout cela, std :: aligné_storage peut vous aider.

 struct Value { // ... private: using JsonNative = third_party::Json; const JsonNative* Ptr() const noexcept; JsonNative* Ptr() noexcept; constexpr std::size_t kImplSize = 32; constexpr std::size_t kImplAlign = 8; std::aligned_storage_t<kImplSize, kImplAlign> data_; }; 

Le seul problème: nous devons définir la taille et l'alignement de chaque wrapper - nous allons créer notre modèle de bouton avec les paramètres <T, SizeT, AlignmentT>, utiliser des valeurs arbitraires et ajouter au destructeur une vérification que nous avons tout deviné:

 ~FastPimpl() noexcept { validate<sizeof(T), alignof(T)>(); Ptr()->~T(); } template <std::size_t ActualSize, std::size_t ActualAlignment> static void validate() noexcept { static_assert( Size == ActualSize, "Size and sizeof(T) mismatch" ); static_assert( Alignment == ActualAlignment, "Alignment and alignof(T) mismatch" ); } 

Puisque T a déjà été déterminé lors du traitement du destructeur, ce code sera démonté correctement et au stade de la compilation sous forme d'erreurs, il affichera la taille nécessaire et les valeurs d'alignement qui doivent être saisies. Ainsi, au prix d'un début de compilation supplémentaire, nous nous débarrassons de l'allocation dynamique des classes encapsulées, masquons l'API dans un fichier .cpp avec l'implémentation, et obtenons également une conception plus adaptée à la mise en cache par le processeur.

La journalisation et l'analyse semblaient moins impressionnantes et ne seront donc pas mentionnées dans cette revue.

Les diapositives du rapport sont disponibles sur le lien: [«Trucs de taxi C ++»]

Techniques modernes pour garder votre code SEC, Björn Fahller


Dans cet exposé, Björn Fahller montre plusieurs façons différentes de traiter les défauts stylistiques tels que les vérifications conditionnelles répétées:

 assert(a == IDLE || a == CONNECTED || a == DISCONNECTED); 

Est-ce familier? En utilisant plusieurs techniques C ++ puissantes qui sont apparues dans les normes récentes, vous pouvez implémenter gracieusement la même fonctionnalité sans la moindre perte de performances. Comparez:

 assert(a == any_of(IDLE, CONNECTED, DISCONNECTED)); 

Pour traiter un nombre illimité de vérifications, vous êtes immédiatement invité à utiliser des modèles variadiques et des expressions de repli. Supposons que nous voulons vérifier l'égalité de plusieurs variables avec l'élément enum'a state_type. La première chose qui me vient à l'esprit est d'écrire la fonction d'assistance is_any_of:

 enum state_type { IDLE, CONNECTED, DISCONNECTED }; template <typename ... Ts> bool is_any_of(state_type s, const Ts& ... ts) { return ((s == ts) || ...); } 

Un tel résultat intermédiaire est décevant. Jusqu'à présent, le code ne devient pas lisible:

 assert(is_any_of(state, IDLE, DISCONNECTING, DISCONNECTED)); 

Les paramètres de modèle non-type aideront à améliorer un peu la situation. Avec leur aide, nous transférons les éléments énumérés enum vers la liste des paramètres du modèle:

 template <state_type ... states> bool is_any_of(state_type t) { return ((t == states) | ...); } assert(is_any_of<IDLE, DISCONNECTING, DISCONNECTED>(state)); 

En utilisant auto dans un paramètre de modèle non typique (C ++ 17), l'approche est simplement généralisée aux comparaisons non seulement avec les éléments state_type, mais aussi avec les types primitifs qui peuvent être utilisés comme paramètres de modèle non-type:

 template <auto ... alternatives, typename T> bool is_any_of(const T& t) { return ((t == alternatives) | ...); } 

Grâce à ces améliorations incrémentielles, la syntaxe superficielle souhaitée pour la vérification est obtenue:

 template <class ... Ts> struct any_of : private std::tuple<Ts ...> { //      tuple        using std::tuple<Ts ...>::tuple;        template <typename T>        bool operator ==(const T& t) const {                return std::apply(                        [&t](const auto& ... ts) {                                return ((ts == t) || ...);                        },                        static_cast<const std::tuple<Ts ...>&>(*this));        } }; template <class ... Ts> any_of(Ts ...) -> any_of<Ts ... >; assert(any_of(IDLE, DISCONNECTING, DISCONNECTED) == state); 

Dans cet exemple, le guide de déduction sert à inviter les paramètres de structure de modèle souhaités à un compilateur qui connaît les types d'arguments du constructeur.

Plus intéressant. Bjorn apprend à généraliser le code résultant pour les opérateurs de comparaison en plus de ==, puis pour les opérations arbitraires. Avec l'exemple d'utilisation, des fonctionnalités telles que l'attribut no_unique_address (C ++ 20) et les paramètres de modèle dans les fonctions lambda (C ++ 20) sont expliquées. (Oui, maintenant la syntaxe lambd est encore plus facile à retenir - ce sont quatre paires consécutives de parenthèses de toutes sortes.) La solution finale utilisant des fonctions comme parties constructeurs me réchauffe vraiment l'âme, sans parler de l'expression de tuple dans les meilleures traditions du calcul lambda.

Au final, n'oubliez pas de mettre un gloss:

  • Rappelez-vous que les lambdas sont constexpr gratuitement;
  • Ajoutez une transmission parfaite et regardez sa syntaxe laide appliquée au pack de paramètres dans la fermeture lambda;
  • Donnons au compilateur plus d'options pour les optimisations avec noexcept conditionnel;
  • Nous nous occuperons d'une sortie d'erreur plus claire dans les modèles en raison des valeurs de retour explicites des lambdas. Cela obligera le compilateur à effectuer plus de vérifications avant d'appeler réellement la fonction de modèle - au stade de la vérification de type.

Pour plus de détails, reportez-vous aux supports de cours:


Nos impressions


Notre première participation à C ++ Russia était connue pour sa richesse. Il y avait une impression de C ++ Russia comme un événement émotionnel, où la frontière entre l'apprentissage et la communication en direct n'est presque pas perceptible. Tout, de l'humeur des intervenants aux compétitions des partenaires de l'événement, est propice à des discussions animées. Le contenu de la conférence, qui se compose de rapports, couvre un assez large éventail de sujets, y compris les innovations C ++, des exemples tirés de la pratique de grands projets et des considérations architecturales idéologiques. Mais il serait injuste de priver l'attention de la composante sociale de l'événement, ce qui aide à surmonter les barrières linguistiques par rapport non seulement au C ++.

Nous remercions les organisateurs de la conférence de l'opportunité de participer à un tel événement!
Vous pouvez voir le post des organisateurs sur le passé, le présent et l'avenir de C ++ Russia sur le blog JUG Ru .

Merci d'avoir lu, et nous espérons que notre récit des événements s'est avéré utile!

Source: https://habr.com/ru/post/fr481358/


All Articles