Bonjour à tous et bienvenue dans cet article de la série L’arrivée du C++17, qui présente les éléments qui ont été dépréciés dans le standard C++17.
C++17 a déprécié un certain nombre d’éléments du langage, je vous propose donc de les regarder ensemble.
shared_ptr::unique
La fonction membre unique de std::shared_ptr a été dépréciée en C++17, au travers de la proposition P0501, à cause des risques qu’elle présente dans les environnements concurrents.
Ce thread sur stackoverflow explique pas mal le problème. Grossièrement, la fonction unique s’appuie sur use_count qui retourne le nombre de shared_ptr qui managent ce même objet. Or, cette valeur est approximative dans un environnement concurrent.
Il est donc possible que unique retourne true alors que le pointeur n’est pas unique, par exemple si un autre thread a accès à ce pointeur :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
int main() { int result = 0; auto sptr = std::make_shared<int>(0); // Start another thread std::thread t([&sptr]{ /* ... */ if(sptr && sptr.unique()) // (1) /* .. */ } }); /* .. */ auto sptr2 = sptr; // (2) /* .. */ } |
Ici, (1) et (2) sont exécutés dans un ordre non déterministe. Si (2) survient après (1), la condition en (1) sera vraie alors que sptr2 sera possiblement créé par la suite.
std::result_of
La pR604 demande la dépréciation de std::result_of, remplacé par un nouveau trait std::invoke_result. L’helper std::result_of_t est également déprécié.
std::result_of, introduit en C++11, est un trait permettant de récupérer le type de retour d’une fonction à la compilation. Plusieurs problèmes ont été reportés sur l’implémentation de std::result_of, qui utilise le function-type encoding (associé à la SFINAE depuis C++14):
1 2 3 4 5 |
template< class > class result_of; // not defined template< class F, class... ArgTypes > class result_of<F(ArgTypes...)>; |
Basiquement, dans certains cas, cette implémentation tentait de former le type F(ArgTypes...) où F était un type-fonction appelé avec les arguments ArgTypes... plutôt que le type de retour. Par conséquent, certains problèmes ont été remontés. La page de result_of sur cppreference.com indique les cas où std::result_of n’a pas le comportement attendu.
La proposition demande un certain nombre de changements, parmi lesquels l’utilisation d’une liste de paramètres template classiques pour std::result_of. Elle suggère aussi de déprécier std::result_of et d’introduire un nouveau nom à la place, de manière à ne pas casser le code existant. std::invoke_result a été choisi :
1 2 |
template< class F, class... ArgTypes> class invoke_result; |
<codecvt>
La proposition p0618R0 demande la dépréciation de l’entête <codecvt>. std::wstring_convert et std::wbuffer_convert de l’entête <locale> sont également dépréciés.
Les raisons énoncées sont des problèmes de sécurité (en cas d’encodage UTF incorrect notamment) et une spécification incomplète. L’entête est déprécié en attendant qu’une nouvelle solution de remplacement soit proposée, mais il s’agit toujours de la seule façon standard de convertir les encodages, malgré ses défauts.
Certains entêtes C
La P0063R3 indique que C++17 devrait faire référence à C11 plutôt qu’à C99. La proposition répertorie donc un certain nombre de changements, notamment la dépréciation des entêtes <ccomplex>, <cstdalign>, <cstdbool>, et <ctgmath>.
Notez que seuls les headers C++ sont dépréciés, une première version de la proposition avait suggéré de déprécier également les entête C ( <complex.h>, <stdalign.h>, <stdbool.h>, et <tgmath.h>) mais l’idée n’a pas été gardée.
Notez que la proposition indique également que les entêtes <stdatomic.h>, <stdnoreturn.h> and <threads.h> issus de C11 sont ignorés par le standard C++, qui propose déjà ces fonctionnalités sous une autre forme ( <stdatomic.h> et <threads.h> sont de toute façon optionnels en C11).
Divers
Un petit dernier pour la route : std::memory_order_consume.
En réalité, celui-ci n’est pas déprécié à proprement parler, mais la P0371 propose de décourager son usage de façon temporaire : “SG1 did not want to officially deprecate memory_order_consume, as was proposed in Revision 0. But we did want to inform users of the problem. The following reflects this compromise.”.
Pour ceux qui voudraient plus de détails sur le fonctionnement des contraintes d’ordonnancement de mémoire et particulièrement de std::memory_order_consume, je vous propose ce lien. Il s’agit d’une des six valeurs de l’enumération std::memory_order.
memory_order_consume est une contrainte moins forte que memory_order_acquire, ce qui signifie que partout où vous utilisez une sémantique consume, vous pouvez la remplacer sans problème par une sémantique acquire. L’objectif était d’autoriser des optimisations pour consume, lorsque les garanties supplémentaires d’acquire ne sont pas nécessaires.
Ce qu’indique le document, c’est qu’avec la spécification actuelle, il n’existe pas d’implémentation qui a réussi à profiter de ces optimisations : “Implementations have found it infeasible to provide performance better than that of memory_order_acquire”. En pratique, beaucoup d’implémentations se contentent de traiter memory_order_consume comme memory_order_acquire.
Pour autant, cette valeur n’est pas dépréciée, mais le comité conseille d’utiliser memory_order_acquire tant qu’une révision de spécification n’aura pas été faite.
C++20
Qu’en est-il pour C++20 ?
std::shared_ptr::unique et std::result_of seront retirés du standard. Concernant <codecvt>, il n’y aura à priori pas de changement tant qu’une solution de remplacement n’aura pas été trouvée, de même que pour std::memory_order_consume. Je n’ai pas non plus trouvé de proposition pour le retrait des entêtes C présentés précédemment avec C++20.
De la même manière que certaines fonctionnalités dépréciées en C++17 seront supprimées pour C++20, le C++17 a apporté son lot de suppressions, que je vous présenterai dans un prochain article. Merci de votre lecture et à bientôt !
Références et ressources
- [EN] open-std.org | P0501R0 “Proposed Resolution for CA 14 (shared_ptr use_count/unique”
- [EN] stackoverflow.com | “Why is std::shared_ptr::unique() deprecated ?”
- [EN] open-std.org | PR604R0 “Resolving GB 55, US 84, US 85, US 86”
- [EN] cppreference.com | result_of / invoke_result
- [EN] open-std.org | P0618R0 “Deprecating <codecvt>”
- [EN] open-std.org | P0063R3 “C++17 should refer to C11 instead of C99”
- [EN] open-std.org | P0371R1 “Temporarily discourage memory_order_consume”
- [EN] preshing.org | “The purpose of memory_order_consume”
You must log in to post a comment.