Encuentro el comportamiento de std::string::find
ser inconsistente con los contenedores estándar de C ++.
P.ej
std::map<int, int> myMap = {{1, 2}};
auto it = myMap.find(10); // it == myMap.end()
Pero por una cuerda,
std::string myStr = "hello";
auto it = myStr.find('!'); // it == std::string::npos
¿Por qué no debería la myStr.find('!')
devolución fallida en myStr.end()
lugar de std::string::npos
?
Dado que std::string
es algo especial en comparación con otros contenedores, me pregunto si hay alguna razón real detrás de esto. (Sorprendentemente, no pude encontrar a nadie cuestionando esto en ninguna parte).
c++
stdstring
c++-standard-library
Sumudu
fuente
fuente
std::string
internamente se compone de personajes que son elementos de bajo costo (en lo que respecta a la memoria). Y, además, el carácter es el único tipo questd::string
puede contener. Por otro lado,std::map
consta de elementos más complejos. Además, la especificación destd::map::find
dice que se supone que debe encontrar un elemento, y la especificación destd::string::find
dice que su tarea es encontrar la posición.Respuestas:
Para empezar,
std::string
se sabe que la interfaz es hinchada e inconsistente, vea Gotw84 de Herb Sutter sobre este tema. Pero, sin embargo, hay un razonamiento detrás destd::string::find
devolver un índice:std::string::substr
. Esta función de miembro de conveniencia opera en índices, p. Ej.Puede implementar de
substr
modo que acepte iteradores en la cadena, pero no tendríamos que esperar mucho tiempo para recibir quejas fuertes que nostd::string
se pueden usar y que no son intuitivas. Entonces, dado questd::string::substr
acepta índices, ¿cómo encontraría el índice de la primera aparición de'd'
en la cadena de entrada anterior para imprimir todo a partir de esta subcadena?Esto también podría no ser lo que quieres. Por lo tanto, podemos dejar que
std::string::find
devuelva un índice, y aquí estamos:Si desea trabajar con iteradores, use
<algorithm>
. Te permiten lo anterior comofuente
std::string::find
aún podría devolversize()
, en lugar denpos
mantener la compatibilidad consubstr
, evitando al mismo tiempo varias ramificaciones adicionales.std::string::substr
ya cubre el caso "comenzar aquí hasta el final" con un parámetro predeterminado para el segundo índice (npos
). Supongo que regresarsize()
también sería confuso y tener un centinela literal comonpos
podría ser la mejor opción.std::string::find
devuelve un iterador,std::string::substr
probablemente también aceptaría un iterador para la posición de inicio. Su ejemplo con find se vería igual en ambos casos en este mundo alternativo.std::string::substr
con un argumento iterador se abre la puerta para otro caso de UB (además del escenario pasado-final que igualmente puede suceder con índices o iteradores): pasar un iterador que se refiere a otra cadena.Esto se debe a que
std::string
tiene dos interfaces:std::string
específicosstd::string::find
forma parte de la interfaz basada en índices y, por lo tanto, devuelve índices.Se usa
std::find
para usar la interfaz general basada en iterador.Úselo
std::vector<char>
si no desea la interfaz basada en índice (no haga esto).fuente