Bugs C ++ 20. Résultats de la réunion à Belfast

L'autre jour, il y a eu une réunion du comité de normalisation du langage de programmation C ++ à Belfast. Environ 400 commentaires sur le C ++ 20 ont été envoyés par les représentants des pays au comité, et la moitié d'entre eux ont réussi à y faire face.

Sous la coupe, vous attendez les résultats des discussions des commentaires russes (oui, VOS commentaires sur C ++ 20), quelques commentaires d'autres pays, et bien sûr le nouveau C ++ 23 approprié (Executors!).

Tous ces problèmes avec C ++ que les gens ont mentionnés sur le site stdcpp.ru , dans le chat @ProCxx , au travail dans Yandex.Taxi, ou en personne lors de conférences, nous les avons formalisés sous forme de commentaires sur C ++ 20. Et donc qu'est-ce qui en est arrivé ...

std :: atomic <int> a {}; et std :: atomic <int> b;


Cela peut sembler étrange, mais les variables a et b ne sont pas initialisées à 0. Pour initialiser une variable atomique à zéro, il a fallu écrire std :: atomic <int> avec {0};

Ce comportement n'est pas du tout évident et de nombreux développeurs se sont brûlés. Le comité a accepté notre remarque sur la norme, et en C ++ 20, les constructeurs par défaut pour std :: atomic_flag et std :: atomic initialiseront les variables en clair et T (), respectivement.

std :: launder


À partir de C ++ 17, la norme a une fonction effrayante std :: launder. Les membres du comité pensaient que les développeurs de bibliothèques standard et les utilisateurs ordinaires sauraient comment y faire face.

En pratique, il s'est avéré que dans certains cas, cette fonction ne pouvait pas être utilisée. Il est extrêmement évident qu'il est nécessaire en principe:

struct C { const int c; }; std::vector<C> v = {C{1}}; v.pop_back(); v.push_back(C{2}); assert(v.back().c == 2); // ]:-> 

Si vous suivez strictement la lettre de la norme, en fonction de l'implémentation de la bibliothèque standard, des fonctionnalités du compilateur et de la phase de lune, assert peut réussir ou échouer.

En discutant du problème, il s'est avéré que l'optimisation, pour le bien de laquelle la norme décrivait un comportement aussi étrange, n'était implémentée que dans l'un des compilateurs et n'apportait pas une amélioration tangible des performances.

Donc, à partir de C ++ 20, vous pouvez stocker en toute sécurité des structures avec des liens et des champs constants dans std :: optional, std :: variant, std :: vector, std :: deque, etc. Maintenant, placement new applique automatiquement une partie de la logique std: : blanchiment.

* ceci chez les constructeurs


C'est l'un des commentaires où un échec nous attendait:

 struct C { C(C&& other) noexcept : initial_(other.initial_) , secondary_(other.initial_) // O_O {} int initial_; int secondary_; }; 

Selon les règles actuelles, dans la ligne avec O_O, le compilateur a le droit de supposer que & other == this et, en conséquence, une ligne ci-dessus, nous avons réécrit la valeur de other.initial_ et elle doit être relue.

En d'autres termes, le compilateur a le droit de supposer qu'une classe qui n'a pas encore été créée est aliasée avec le paramètre à partir duquel l'objet est construit, et à cause de cela, il peut générer du code non optimal.

Certains compilateurs (par exemple, GCC), croient que les utilisateurs n'écrivent pas une telle honte et pensent que l'aliasing n'est pas possible.

Le comité a rejeté notre remarque «Supposons que le repliement ne soit pas possible». Il s'est avéré que certaines bases de code ont des hacks effrayants où & autres == cela, et les gens ne sont pas encore prêts à leur dire au revoir.

opérateur <=> et programmation intégrée


Pour que l'opérateur du vaisseau spatial fonctionne, vous avez besoin du fichier d'en-tête <compare>. Cependant, il ne figurait pas dans la liste des fichiers d'en-tête disponibles sur toutes les plates-formes (sur les implémentations dites autonomes de la bibliothèque standard qui peuvent être utilisées sur n'importe quel fer).

Maintenant, c'est sur la liste :)

Le reste


Selon nos autres commentaires, le verdict «Pas en C ++ 20» a été rendu:
* Nous voulions que __func__ soit utilisé dans constexpr.
* Nous voulions que le concept n'utilise pas le type incomplet, car sinon vous obtenez plusieurs violations ODR. Mais la remarque a eu un effet positif inattendu: les compilateurs émettent désormais un avertissement si vous utilisez le type incomplet dans require.
* Nous voulions corriger l'opérateur d'affectation pour std :: string afin qu'un tel désordre ne se produise pas:

 basic_string::operator=(charT c): double d = 3.14; std::string s; s = d; // Compiles 

Le comité a suggéré d'écrire un document séparé et de le corriger après C ++ 20.
* Nous voulions tuer l'affectation des lignes temporaires dans std :: string_view:
 std::string foo(); std::string_view sv; sv = foo(); // Compiles... dangling reference 

Le résultat est le même que la remarque précédente: le comité a suggéré d'écrire un document séparé et de le corriger après C ++ 20.
* Nous avons demandé que le code suivant soit compilé:

 #include <type_traits> template <typename... Xs> auto f (Xs...) -> std::invoke_result_t<Xs...>; 

On nous a dit que tout est compliqué, il n'y a pratiquement aucune chance de réparer C ++ 20.

Commentaires d'autres pays


Des changements importants: ajout de constructeurs pour std :: span à partir de types qui satisfont le concept de plages :: contiguous_range. Alors maintenant, span peut être implicitement créé à partir de std :: vector et std :: string. Nous avons également ajouté le constructeur std :: string_view de deux itérateurs qui satisfont le concept de range :: contiguous_iterator.

Des modifications amusantes attendaient <compare>. Au cours des trois dernières années, l'opérateur <=> a beaucoup changé. Il ne participe plus aux comparaisons d'égalité et, en conséquence, un tiers du contenu de <comparer> n'est plus nécessaire. Plusieurs pays l'ont remarqué - ils ont abaissé la norme.

Un grand changement s'est glissé dans des paramètres de modèle non-type. En C ++ 20, il sera possible de passer presque toutes les classes (voir P1907) avec un destructeur constexpr et des membres publics comme paramètre de modèle, même si la classe contient des types ou des liens à virgule flottante.

Nous avons également ajouté le const manquant à différentes parties de la norme, changé les noms et l'ordre des arguments de certaines fonctions nouvelles en C ++ 20. Il existe également de nombreuses modifications pour les concepts et les plages, les abréviations du texte standard et d'autres petites choses.

Numéros TS


ZaMaZaN4iK et moi avons pu remuer le comité avec le document C ++ Numerics Work In Progress. Il existe maintenant des plans napoléoniens pour C ++ 23 pour donner aux utilisateurs un ensemble de nouveaux types de nombres (wide_integer, entier, rationnel), ainsi que des méthodes auxiliaires de bas niveau pour travailler avec les débordements et les alias pratiques.

On m'a dit de préparer une présentation pour la prochaine réunion avec une introduction aux idées pour l'ensemble du comité.

Exécuteurs


Les exécuteurs sont l'une des priorités de C ++ 23. Ils sont nécessaires à la programmation réactive, à la programmation asynchrone (réseau, disque, processus ...), ils sont à la base du délestage de coroutine et devraient fournir une interface unique pour les bibliothèques tierces.

Dans le même temps, les exécuteurs devraient optimiser les algorithmes pour leur implémentation interne. Par exemple, pour le code:

 template <std::input_range Range> void MySort(Range& data) { namespace stdr = std::ranges; std::sort(GetGlobalExecutor(), stdr::begin(data), stdr::end(data), 42); } 

la fonction GetGlobalExecutor () peut retourner:
* exécuteur monothread - il devrait exécuter le std :: sort habituel sur son thread;
* exécuteur multithread - il doit effectuer un tri parallèle;
* Exécuteur GPU - il doit déplacer les données vers la mémoire de la carte vidéo, les trier là et renvoyer les données;
* Exécuteur NUMA - ...
* ...

Jusqu'à présent, pour implémenter une telle fonctionnalité, vous devez faire des objets de point de personnalisation (CPO) effrayants, transformer chaque algorithme en eux. Le comité n'a pas aimé ...

Mais au moins, ils ont pré-approuvé le P0443 - l'interface de base. Toutes les phrases suivantes pour les exécuteurs devront être écrites sous forme de correctifs pour P0443.

Au lieu de totaux


Maintenant, nous sommes séparés du C ++ 20 par une seule réunion de comité. Encore un peu ...

Eh bien, tous ceux qui veulent discuter avec des représentants du comité en direct - regardez les mitaps et les conférences C ++ (*) :
* Corehard à Minsk
* C ++ Sibérie 2020
* C ++ Russie 2020
* St. Petersburg C ++ User Group
* Meetup C ++ 2019 à Moscou

(*) Life hack: vous n'êtes pas obligé de payer un ticket de conférence si vous êtes conférencier.

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


All Articles