Bonjour à tous et bienvenue dans cet article qui traite des nouveaux attributs ajoutés dans C++20.
C++20 intègre trois nouveau attributs : likely, unlikely et no_unique_address. Bon en réalité il y en a six, mais les trois autres ( expect, ensures et assert) auront leur article dédié qui traitera des ajouts de programmation par contrat.
likely et unlikely
Ces deux attributs ont été introduits pour permettre d’indiquer au compilateur qu’une branche est plus probable que l’autre. likely, respectivement unlikely, peut être assigné à un label ou une expression pour indiquer que le résultat sera le plus souvent true, respectivement false :
1 2 3 4 5 6 7 8 |
int f(int i) { switch(i) { case 1: return 1; [[likely]] case 2: return 2; [[unlikely]] default: return 3; } return 2; } |
Ici, le compilateur sait que la valeur 2 est la plus probable, et que les valeurs autres que 1 et 2 sont peu probables. Il peut alors effectuer des optimisations supplémentaires puisqu’il a des informations supplémentaires sur le flot de contrôle.
La p0479r0, dont sont issus ces attributs, rappelle cependant que ceux-ci sont supposés être utilisés sur des points critiques qui ont été détectés sur du code existant principalement. L’utilisation de ces attributs peut facilement détériorer la performance en cas de mauvais usage.
Ces attributs peuvent être aussi appliqués aux branchements if, d’après le papier (cependant GCC 8.1.0 et Clang 5.0.0 (avec -std=c++2a)) n’acceptent pas cette syntaxe pour le moment) :
1 2 3 |
if ([[unlikely]] foo()) { do_something(); } |
no_unique_address
L’attribut no_unique_address est destiné à indiquer qu’une variable membre n’a pas besoin d’avoir une adresse séparée des autres membres de la classes. Cela revient à autoriser un équivalent de l’EBO pour un membre d’une classe.
Je vais reprendre l’exemple de cppreference, qui est plutôt bien fait :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
struct Empty {}; // empty class struct X { int i; Empty e; }; struct Y { int i; [[no_unique_address]] Empty e; }; int main() { // the size of any object of empty class type is at least 1 static_assert(sizeof(Empty) >= 1); // at least one more byte is needed to give e a unique address static_assert(sizeof(X) >= sizeof(int) + 1); // empty member optimized out static_assert(sizeof(Y) == sizeof(int)); } |
Ici, Empty est une empty class, c’est à dire qu’elle ne contient aucune donnée membre. Puisque le C++ impose que même une classe vide fait une taille d’au moins 1 byte, la première assertion est donc vraie.
La classe X contient une donnée membre de type Empty, la classe X a donc une taille au moins égale à la taille d’un int plus un byte, soit sizeof(int) + 1 comme le confirme la seconde assertion.
La classe Y contient elle aussi une donnée membre de type Empty, mais accompagnée de l’attribut no_unique_address. Dans ce cas, le compilateur est autorisé à optimiser ce membre de manière à ne lui faire occuper aucune place. Par conséquent, la taille de Y est égale à la taille d’un int, le membre e n’occupant pas d’espace en mémoire.
no_unique_address est donc intéressant lorsqu’on utilise une membre qui n’a pas besoin d’occuper de l’espace mémoire.
Voilà donc trois des six nouveaux attributs de C++20. Les trois derniers seront présentés dans un prochain article. Merci de m’avoir lu et à bientôt.
You must log in to post a comment.