Acho que o comportamento std::string::find
é inconsistente com os contêineres C ++ padrão.
Por exemplo
std::map<int, int> myMap = {{1, 2}};
auto it = myMap.find(10); // it == myMap.end()
Mas para uma corda,
std::string myStr = "hello";
auto it = myStr.find('!'); // it == std::string::npos
Por que a falha não deveria myStr.find('!')
retornar em myStr.end()
vez de std::string::npos
?
Como o std::string
é um pouco especial quando comparado com outros contêineres, estou me perguntando se há alguma razão real por trás disso. (Surpreendentemente, eu não consegui encontrar ninguém questionando isso em lugar nenhum).
c++
stdstring
c++-standard-library
Sumudu
fonte
fonte
std::string
internamente consiste em caracteres que são elementos baratos (em relação à memória). Além disso, o caractere é o único tipo questd::string
pode conter. Por outro lado,std::map
consiste em elementos mais complexos. Além disso, a especificação destd::map::find
diz que é suposto encontrar um elemento, e a especificação destd::string::find
diz que sua tarefa é encontrar a posição.Respostas:
Para começar,
std::string
sabe-se que a interface é inchada e inconsistente, consulte Gotw84 de Herb Sutter sobre este tópico. Mas, no entanto, há um raciocínio por trásstd::string::find
retornando um índice:std::string::substr
. Esta função de membro de conveniência opera em índices, por exemploVocê pode implementar de
substr
forma que ele aceite iteradores na cadeia de caracteres, mas não precisaremos esperar muito tempo por reclamações altas questd::string
são inutilizáveis e contra-intuitivas. Então, considerando questd::string::substr
aceita índices, como você encontraria o índice da primeira ocorrência'd'
na string de entrada acima para imprimir tudo a partir dessa substring?Isso também pode não ser o que você deseja. Portanto, podemos deixar
std::string::find
retornar um índice, e aqui estamos:Se você deseja trabalhar com iteradores, use
<algorithm>
. Eles permitem que você acimafonte
std::string::find
ainda pode retornarsize()
, em vez denpos
manter a compatibilidade comsubstr
, além de evitar várias ramificações extras.std::string::substr
já cubra o caso "comece aqui até o fim" com um parâmetro padrão para o segundo índice (npos
). Eu acho que voltarsize()
também seria confuso e ter uma sentinela literal comonpos
pode ser a melhor escolha ?!std::string::find
retornar um iterador,std::string::substr
provavelmente também aceitaria um iterador para a posição inicial. Seu exemplo com find seria o mesmo nos dois casos neste mundo alternativo.std::string::substr
com um argumento de iterador, abre a porta para mais um caso de UB (além do cenário passado que pode igualmente acontecer com índices ou iteradores): passar um iterador que se refere a outra sequência.Isso ocorre porque
std::string
há duas interfaces:std::string
específica baseada em índicestd::string::find
faz parte da interface baseada em índice e, portanto, retorna índices.Use
std::find
para usar a interface geral baseada no iterador.Use
std::vector<char>
se você não quiser a interface baseada em índice (não faça isso).fonte