J'utilise une bibliothèque interne qui a été conçue pour imiter une bibliothèque C ++ proposée , et au cours des dernières années, je vois son interface passer de l'utilisation std::string
àstring_view
.
Je change donc consciencieusement mon code, pour me conformer à la nouvelle interface. Malheureusement, ce que je dois transmettre est un paramètre std :: string et quelque chose qui est une valeur de retour std :: string. Donc, mon code a changé de quelque chose comme ceci:
void one_time_setup(const std::string & p1, int p2) {
api_class api;
api.setup (p1, special_number_to_string(p2));
}
à
void one_time_setup(const std::string & p1, int p2) {
api_class api;
const std::string p2_storage(special_number_to_string(p2));
api.setup (string_view(&p1[0], p1.size()), string_view(&p2_storage[0], p2_storage.size()));
}
J'ai vraiment vois pas ce que ce changement m'a apporté en tant que client API, à part plus de code (pour éventuellement bousiller). L'appel d'API est moins sûr (car l'API ne possède plus le stockage pour ses paramètres), a probablement sauvé le travail de mon programme 0 (en raison des optimisations de déplacement que les compilateurs peuvent faire maintenant), et même s'il a économisé du travail, ce ne serait que quelques allocations qui ne seront pas et ne seront jamais faites après le démarrage ou dans une grande boucle quelque part. Pas pour cette API.
Cependant, cette approche semble suivre les conseils que je vois ailleurs, par exemple cette réponse :
En passant, depuis C ++ 17 vous devez éviter de passer un const std :: string & en faveur d'un std :: string_view:
Je trouve ce conseil surprenant, car il semble préconiser le remplacement universel d'un objet relativement sûr par un objet moins sûr (essentiellement un pointeur et une longueur glorifiés), principalement à des fins d'optimisation.
Alors, quand string_view devrait- il être utilisé et quand ne devrait-il pas l'être?
std::string_view
directement le constructeur, vous devez simplement passer les chaînes à la méthode en prenant unstd::string_view
directement et il se convertira automatiquement.<string>
tête et se produit automatiquement. Ce code est trompeur et faux.Réponses:
std::string
(non const, non-ref). Cette option vous donne également le choix de déplacer explicitement une valeur si vous savez qu'elle ne sera plus jamais utilisée dans le contexte d'appel.std::string_view
(const, non-ref) c'est parce questring_view
peut gérerstd::string
etchar*
facilement sans problème et sans faire de copie. Cela devrait remplacer tous lesconst std::string&
paramètres.En fin de compte, vous ne devriez jamais avoir besoin d'appeler le
std::string_view
constructeur comme vous.std::string
possède un opérateur de conversion qui gère automatiquement la conversion.la source
std::string_view
faciliter l'utilisation. Si un développeur l'utilise mal dans une situation propriétaire, c'est une erreur de programmation.std::string_view
est strictement non propriétaire.const, non-ref
? Le paramètre étant const est à l'usage spécifique, mais en général est raisonnable comme non-const. Et vous avez manqué 3. Peut accepter des tranchesconst std::string_view &
à la place deconst std::string &
?A
std::string_view
apporte certains des avantages d'unconst char*
à C ++: contrairement àstd::string
, un string_viewstd::string&
.Cela signifie qu'un string_view peut souvent éviter les copies, sans avoir à traiter avec des pointeurs bruts.
Dans le code moderne,
std::string_view
devrait remplacer presque toutes les utilisations desconst std::string&
paramètres de fonction. Cela devrait être une modification compatible avec la source, carstd::string
déclare un opérateur de conversion àstd::string_view
.Ce n'est pas parce qu'une vue de chaîne n'aide pas dans votre cas d'utilisation spécifique où vous devez de toute façon créer une chaîne que c'est une mauvaise idée en général. La bibliothèque standard C ++ a tendance à être optimisée pour la généralité plutôt que pour la commodité. L'argument «moins sûr» ne tient pas, car il ne devrait pas être nécessaire de créer la vue chaîne vous-même.
la source
std::string_view
est l'absence dec_str()
méthode, ce qui entraîne desstd::string
objets intermédiaires inutiles qui doivent être construits et alloués. C'est particulièrement un problème dans les API de bas niveau.abcdef\0
et une vue de chaîne qui pointe vers lacde
sous - chaîne, il n'y a pas de caractère zéro après lee
- la chaîne d'origine a unf
là. La norme note également: «data () peut renvoyer un pointeur vers un tampon qui ne se termine pas par null. Par conséquent, c'est généralement une erreur de passer data () à une fonction qui prend juste un const charT * et attend une chaîne terminée par null. »Je pense que c'est un peu mal comprendre le but de cela. Bien qu'il s'agisse d'une "optimisation", vous devriez vraiment y voir un moyen de vous libérer de l'utilisation d'un
std::string
.Les utilisateurs de C ++ ont créé des dizaines de classes de chaînes différentes. Classes de chaînes de longueur fixe, classes optimisées pour l'authentification unique avec la taille du tampon comme paramètre de modèle, classes de chaînes qui stockent une valeur de hachage utilisée pour les comparer, etc. Certaines personnes utilisent même des chaînes basées sur COW. S'il y a une chose que les programmeurs C ++ aiment faire, c'est d'écrire des classes de chaînes.
Et cela ignore les chaînes qui sont créées et détenues par les bibliothèques C. Des nus
char*
, peut-être avec une taille quelconque.Donc, si vous écrivez une bibliothèque et que vous en prenez une
const std::string&
, l'utilisateur doit maintenant prendre la chaîne qu'il utilisait et la copier dans astd::string
. Peut-être des dizaines de fois.Si vous souhaitez accéder à
std::string
l'interface spécifique à la chaîne de, pourquoi devriez-vous copier la chaîne? C'est un tel gaspillage.Les principales raisons de ne pas prendre a
string_view
comme paramètre sont:Si votre objectif ultime est de passer la chaîne à une interface qui prend une chaîne terminée par NUL (
fopen
, etc.).std::string
est garanti d'être résilié NUL;string_view
n'est pas. Et il est très facile de sous-chaîne une vue pour la rendre non terminée par NUL; la sous-std::string
chaîne a copiera la sous-chaîne dans une plage terminée par NUL.J'ai écrit un type de style string_view spécial terminé par NUL pour exactement ce scénario. Vous pouvez effectuer la plupart des opérations, mais pas celles qui rompent son état terminé par NUL (découpage de la fin, par exemple).
Problèmes à vie. Si vous avez vraiment besoin de copier cela
std::string
ou que le tableau de caractères dure plus longtemps que l'appel de fonction, il est préférable de le déclarer dès le début en prenant aconst std::string &
. Ou tout simplementstd::string
comme paramètre de valeur. De cette façon, s'ils ont déjà une telle chaîne, vous pouvez en revendiquer immédiatement la propriété, et l'appelant peut se déplacer dans la chaîne s'il n'a pas besoin d'en conserver une copie.la source
string_view
est un type de lingua franca qui peut fonctionner avec n'importe quoi.string_view
, c'est facile.