Je trouve que le comportement de std::string::find
n'est pas cohérent avec les conteneurs C ++ standard.
Par exemple
std::map<int, int> myMap = {{1, 2}};
auto it = myMap.find(10); // it == myMap.end()
Mais pour une chaîne,
std::string myStr = "hello";
auto it = myStr.find('!'); // it == std::string::npos
Pourquoi le myStr.find('!')
retour échoué ne devrait-il pas myStr.end()
plutôt std::string::npos
?
Étant donné que le std::string
est quelque peu spécial par rapport à d'autres conteneurs, je me demande s'il y a une vraie raison derrière cela. (Étonnamment, je n'ai trouvé personne qui remette cela en question).
std::string
interne, se compose de caractères qui sont des éléments peu coûteux (en ce qui concerne la mémoire). Et, en outre, le caractère est le seul typestd::string
pouvant contenir. D'autre part, sestd::map
compose d'éléments plus complexes. De plus, la spécification destd::map::find
dit qu'il est censé trouver un élément, et la spécification destd::string::find
dit que sa tâche est de trouver la position.Réponses:
Pour commencer, l'
std::string
interface est bien connue pour être gonflée et incohérente, voir Gotw84 de Herb Sutter sur ce sujet. Mais néanmoins, il y a un raisonnement derrière lestd::string::find
retour d' un indice:std::string::substr
. Cette fonction de membre de commodité fonctionne sur des indices, par exempleVous pouvez implémenter de
substr
telle sorte qu'il accepte les itérateurs dans la chaîne, mais nous n'aurions pas besoin d'attendre longtemps pour les plaintes bruyantesstd::string
inutilisables et contre-intuitives. Donc, étant donné que celastd::string::substr
accepte les indices, comment trouveriez-vous l'indice de la première occurrence de'd'
dans la chaîne d'entrée ci-dessus afin d'imprimer tout à partir de cette sous-chaîne?Ce n'est peut-être pas non plus ce que vous voulez. On peut donc laisser
std::string::find
retourner un indice, et nous voici:Si vous souhaitez travailler avec des itérateurs, utilisez
<algorithm>
. Ils vous permettent de ce qui précède commela source
std::string::find
pourrait toujours retournersize()
, au lieu denpos
, conserver la compatibilité avecsubstr
, tout en évitant plusieurs brances supplémentaires.std::string::substr
couvre déjà le cas "commencer ici jusqu'à la fin" avec un paramètre par défaut pour le deuxième index (npos
). Je suppose que revenirsize()
serait aussi déroutant et avoir une sentinelle littérale commenpos
pourrait être le meilleur choix?!std::string::find
renvoie un itérateur,std::string::substr
accepterait probablement aussi un itérateur pour la position de départ. Votre exemple avec find serait le même dans les deux cas dans ce monde alternatif.std::string::substr
avec un argument itérateur, cela ouvre la porte à un autre cas UB (en plus du scénario de fin de cycle qui peut tout aussi bien se produire avec des indices ou des itérateurs): passer un itérateur qui fait référence à une autre chaîne.En effet,
std::string
avoir deux interfaces:std::string
spécifiquestd::string::find
fait partie de l' interface basée sur un index et renvoie donc des indices.Utilisez
std::find
pour utiliser l'interface générale basée sur un itérateur.À utiliser
std::vector<char>
si vous ne voulez pas l'interface basée sur l'index (ne faites pas cela).la source