Avantages de l’utilisation d’un littéral défini par l’utilisateur pour les chaînes au lieu du littéral de chaîne

Le sujet des chaînes dans la documentation du SO indiquait, dans la section Remarques:

Depuis C ++ 14, au lieu d’utiliser "foo" , il est recommandé d’utiliser "foo"s , car s est un littéral de chaîne, qui convertit le caractère const char * "foo" en std::ssortingng "foo" .

Le seul avantage que je vois utiliser

 std::ssortingng str = "foo"s; 

au lieu de

 std::ssortingng str = "foo"; 

est que dans le premier cas, le compilateur peut effectuer une copie-élision (je pense), ce qui serait plus rapide que l’appel du constructeur dans le second cas.

Néanmoins, ceci est (pas encore) garanti, donc le premier peut aussi appeler un constructeur, le constructeur de la copie.

Ignorer les cas où il est nécessaire d’utiliser std::ssortingng littéraux std::ssortingng comme

 std::ssortingng str = "Hello "s + "World!"s; 

y a-t-il un avantage à utiliser std::ssortingng littéraux std::ssortingng au lieu des littéraux const char[] ?

    Si vous faites partie de la foule “Almost Always Auto”, alors la UDL est très importante. Cela vous permet de faire ceci:

     auto str = "Foo"s; 

    Et donc, str sera un véritable std::ssortingng , pas un const char* . Il vous permet donc de décider quand faire quoi.

    Ceci est également important pour la déduction du type de retour automatique:

     []() {return "Foo"s;} 

    Ou toute forme de déduction de type, vraiment:

     template void foo(T &&t) {...} foo("Foo"s); 

    Le seul avantage que j’utilise en utilisant […] au lieu de […] est que dans le premier cas, le compilateur peut effectuer une élision de copie (je pense), ce qui serait plus rapide que l’appel du constructeur dans le second cas.

    La copie-élision n’est pas plus rapide que l’appel du constructeur. De toute façon, vous appelez l’un des constructeurs de l’object. La question est de savoir laquelle :

     std::ssortingng str = "foo"; 

    Cela provoquera un appel au constructeur de std::ssortingng qui prend un const char* . Mais comme std::ssortingng doit copier la chaîne dans son propre stockage, elle doit avoir la longueur de la chaîne pour le faire. Et comme il ne connaît pas la longueur, ce constructeur est obligé d’utiliser strlen pour l’obtenir (techniquement, char_traits::length , mais cela ne va probablement pas être beaucoup plus rapide).

    Par contre:

     std::ssortingng str = "foo"s; 

    Cela utilisera le modèle UDL qui a ce prototype:

     ssortingng operator "" s(const char* str, size_t len); 

    Voir, le compilateur connaît la longueur d’un littéral de chaîne. Ainsi, le code UDL passe un pointeur sur la chaîne et sa taille. Et donc, il peut appeler le constructeur std::ssortingng qui prend un const char* et un size_t . Il n’y a donc pas besoin de calculer la longueur de la chaîne.

    Le conseil en question n’est pas pour vous de faire le tour et de convertir chaque utilisation d’un littéral dans la version s . Si vous êtes d’accord avec les limitations d’un tableau de caractères, utilisez-le. Le conseil est que, si vous voulez stocker ce littéral dans une std::ssortingng , il est préférable de le faire alors que c’est toujours un littéral et non un nébuleux const char* .

    Le conseil d’utilisation de "blah"s n’a rien à voir avec l’efficacité et tout à voir avec l’exactitude du code novice.

    Les novices C ++ qui n’ont pas d’arrière-plan en C ont tendance à supposer que "blah" traduit par un object de type chaîne raisonnable. Par exemple, pour que l’on puisse écrire des choses comme "blah" + 42 , qui fonctionne dans de nombreux langages de script. Avec "blah" + 42 en C ++, on se heurte simplement à Undefined Behavior, en adressant au-delà de la fin du tableau de caractères.

    Mais si ce littéral de chaîne est écrit en tant que "blah"s alors on obtient une erreur de compilation, ce qui est beaucoup préférable.

    De plus, UDL rend plus facile d’avoir \0 dans la chaîne

     std::ssortingng s = "foo\0bar"s; // s contains a \0 in its middle. std::ssortingng s2 = "foo\0bar"; // equivalent to "foo"s 
    1. L’utilisation d’un littéral de chaîne C ++ signifie que nous n’avons pas besoin d’appeler strlen pour calculer la longueur. Le compilateur le sait déjà.
    2. Peut autoriser les implemetations de bibliothèque où les données de chaîne pointent vers la mémoire dans un espace global en utilisant des littéraux C doivent toujours forcer une copie des données à emstackr de la mémoire lors de la construction.