sous - user defined literals c++ 14




Devrais-je comparer un std::string à "string" ou "string" s? (2)

Considérez cet extrait de code:

bool foo(const std::string& s) {
    return s == "hello"; // comparing against a const char* literal
}

bool bar(const std::string& s) {
    return s == "hello"s; // comparing against a std::string literal
}

À première vue , il semble que la comparaison avec un caractère const char* nécessite moins d'instructions d'assemblage 1 , l'utilisation d'un littéral de chaîne conduisant à une construction sur place de std::string .

Cependant, en regardant l' operator==(const char*, const std::string&) reference:

Toutes les comparaisons sont effectuées via la fonction membre compare() .

Si je comprends bien, cela signifie que nous aurons quand même besoin de construire un std::string pour pouvoir effectuer la comparaison. Je suppose donc que la surcharge sera la même à la fin (bien que cachée par l'appel à l' operator== ).

( EDIT: Comme indiqué dans les réponses, j'ai oublié le fait qu'effectivement s.compare(const char*) sera appelé dans foo() , donc bien sûr, aucune construction sur place n'a lieu dans ce cas )

  • Laquelle des comparaisons devrais-je préférer?
  • Une version présente-t-elle des avantages par rapport à l'autre (peut-être dans des situations spécifiques)?

1 Je suis conscient que moins d'instructions de montage ne signifie pas nécessairement un code plus rapide, mais je ne veux pas entrer dans l'analyse comparative micro ici.


Si je comprends bien, cela signifie que nous aurons quand même besoin de construire un std::string pour pouvoir effectuer la comparaison. Je suppose donc que la surcharge sera la même à la fin (bien que cachée par l'appel à l' operator== ).

C'est là que ce raisonnement tourne mal. std::compare n'a pas besoin d'allouer son opérande en tant que chaîne à terminaison NULL dans le style C pour fonctionner. Selon l'une des surcharges:

int compare( const CharT* s ) const; // (4)

4) Compare cette chaîne à la séquence de caractères terminée par un zéro, en commençant par le caractère pointé par s de longueur Traits::length(s) .

Bien que l'affectation ou non soit un détail d'implémentation, il ne semble pas raisonnable qu'une comparaison de séquence le fasse.


Ni.

Si vous voulez être intelligent, comparez-le à "string"sv , qui renvoie std::string_view .

Bien que la comparaison avec un littéral tel que "string" n'entraîne aucune surcharge d'allocation, elle est traitée comme une chaîne terminée par un caractère nul, avec tous les inconvénients concomitants: aucune tolérance pour les éléments null incorporés et les utilisateurs doivent tenir compte du terminateur null.

"string"s effectue une allocation, à l’exception de l’ small-string-optimisation ou de l’ allocation de small-string-optimisation . En outre, l'opérateur obtient la longueur du littéral, pas besoin de compter, et permet les valeurs NULL incorporées.

Enfin, l'utilisation de "string"sv combine les avantages des deux autres approches, en évitant leurs inconvénients respectifs. De plus, un std::string_view est une bête beaucoup plus simple qu'un std::string , surtout si ce dernier utilise l'authentification unique comme tous les modernes.

Du moins depuis C ++ 14 (qui permettait généralement d’allouer des allocations), les compilateurs pourraient théoriquement optimiser toutes les options, à condition de disposer des informations suffisantes (généralement disponibles pour l’exemple) et des efforts nécessaires, selon la règle as-if . Nous n'y sommes pas encore.







string-literals