Uważam zachowanie std::string::find
jest niespójne ze standardowymi kontenerami C ++.
Na przykład
std::map<int, int> myMap = {{1, 2}};
auto it = myMap.find(10); // it == myMap.end()
Ale dla sznurka
std::string myStr = "hello";
auto it = myStr.find('!'); // it == std::string::npos
Dlaczego zamiast nieudanego myStr.find('!')
powrotu ?myStr.end()
std::string::npos
Ponieważ std::string
jest to coś specjalnego w porównaniu z innymi pojemnikami, zastanawiam się, czy jest jakiś prawdziwy powód tego. (Zaskakujące, nigdzie nie znalazłem nikogo, kto by to kwestionował).
c++
stdstring
c++-standard-library
Sumudu
źródło
źródło
std::string
wewnętrznie składają się z znaków, które są niedrogimi elementami (pod względem pamięci). Co więcej, charakter jest jedynym typem, którystd::string
może zawierać. Z drugiej stronystd::map
składa się z bardziej złożonych elementów. Ponadto specyfikacjastd::map::find
mówi, że ma znaleźć element, a specyfikacjastd::string::find
mówi, że jego zadaniem jest znalezienie pozycji.Odpowiedzi:
Po pierwsze,
std::string
interfejs jest dobrze znany jako nadęty i niespójny, patrz Gotw84 Herb Suttera na ten temat. Ale mimo wszystko, istnieje uzasadnieniestd::string::find
zwrotu indeksu:std::string::substr
. Ta funkcja członka wygody działa na indeksach, npMożesz zaimplementować
substr
takie, które akceptuje iteratory w ciągu, ale wtedy nie musielibyśmy długo czekać na głośne skargi, którestd::string
są bezużyteczne i sprzeczne z intuicją. Biorąc pod uwagę, żestd::string::substr
akceptujemy indeksy, w jaki sposób można znaleźć indeks pierwszego wystąpienia'd'
powyższego ciągu wejściowego, aby wydrukować wszystko, zaczynając od tego podłańcucha?To może nie być to, czego chcesz. Dlatego możemy pozwolić
std::string::find
zwrócić indeks, a oto jesteśmy:Jeśli chcesz pracować z iteratorami, użyj
<algorithm>
. Pozwalają ci na powyższe jakoźródło
std::string::find
może jeszcze powrócićsize()
, zamiastnpos
, zachowując zgodność zsubstr
, jednocześnie unikając kilka dodatkowych brances.std::string::substr
już obejmuje przypadek „zacznij tutaj do końca” domyślnym parametrem dla drugiego indeksu (npos
). Wydaje mi się, że powrótsize()
byłby mylący, a posiadanie dosłownego wartownikanpos
może być lepszym wyborem ?!std::string::find
zwróci iterator,std::string::substr
prawdopodobnie również zaakceptuje iterator dla pozycji początkowej. Twój przykład ze znalezieniem wyglądałby tak samo w obu przypadkach w tym alternatywnym świecie.std::string::substr
z argumentem iteratora otwiera drzwi do jeszcze jednej sprawy UB (oprócz scenariusza z przeszłości, który równie dobrze może się zdarzyć z indeksami lub iteratorami): przekazanie iteratora, który odnosi się do innego ciągu.Jest tak, ponieważ
std::string
mają dwa interfejsy:std::string
Specyficzny wskaźnik interfejs opartystd::string::find
jest częścią indeksu interfejsu opartego , dlatego zwraca indeksy.Posługiwać się
std::find
aby użyć ogólnego interfejsu opartego na iteratorze.Użyj,
std::vector<char>
jeśli nie chcesz interfejsu opartego na indeksie (nie rób tego).źródło