Encuentro el comportamiento de std::string::findser 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::stringes 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::stringinternamente 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::stringpuede contener. Por otro lado,std::mapconsta de elementos más complejos. Además, la especificación destd::map::finddice que se supone que debe encontrar un elemento, y la especificación destd::string::finddice que su tarea es encontrar la posición.Respuestas:
Para empezar,
std::stringse 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::finddevolver un índice:std::string::substr. Esta función de miembro de conveniencia opera en índices, p. Ej.Puede implementar de
substrmodo que acepte iteradores en la cadena, pero no tendríamos que esperar mucho tiempo para recibir quejas fuertes que nostd::stringse pueden usar y que no son intuitivas. Entonces, dado questd::string::substracepta í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::finddevuelva un índice, y aquí estamos:Si desea trabajar con iteradores, use
<algorithm>. Te permiten lo anterior comofuente
std::string::findaún podría devolversize(), en lugar denposmantener la compatibilidad consubstr, evitando al mismo tiempo varias ramificaciones adicionales.std::string::substrya 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 comonpospodría ser la mejor opción.std::string::finddevuelve un iterador,std::string::substrprobablemente 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::substrcon 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::stringtiene dos interfaces:std::stringespecíficosstd::string::findforma parte de la interfaz basada en índices y, por lo tanto, devuelve índices.Se usa
std::findpara usar la interfaz general basada en iterador.Úselo
std::vector<char>si no desea la interfaz basada en índice (no haga esto).fuente