Почему `std :: string :: find ()` не возвращает конечный итератор при сбоях? - PullRequest
29 голосов
/ 17 октября 2019

Я считаю, что поведение std::string::find несовместимо со стандартными контейнерами C ++.

Например,

std::map<int, int> myMap = {{1, 2}};
auto it = myMap.find(10);  // it == myMap.end()

Но для строки,

std::string myStr = "hello";
auto it = myStr.find('!');  // it == std::string::npos

Почемуразве неудачный myStr.find('!') возврат myStr.end() вместо std::string::npos?

Поскольку std::string является чем-то особенным по сравнению с другими контейнерами, мне интересно, есть ли какая-то реальная причина этого. (Удивительно, но я не смог найти никого, кто бы это допрашивал).

Ответы [ 2 ]

28 голосов
/ 17 октября 2019

Начнем с того, что интерфейс std::string хорошо известен как раздутый и непоследовательный, см. Статью Gotw84 от Herb Sutter на эту тему. Но, тем не менее, существует причина, по которой std::string::find возвращает индекс: std::string::substr. Эта вспомогательная функция-член работает с индексами, например,

const std::string src = "abcdefghijk";

std::cout << src.substr(2, 5) << "\n";

. Вы можете реализовать substr таким образом, чтобы она принимала итераторы в строку, но тогда нам не пришлось бы долго ждать громких жалоб на то, что std::stringнепригоден и нелогичен. Поэтому, учитывая, что std::string::substr принимает индексы, как найти индекс первого вхождения 'd' в указанной выше входной строке, чтобы распечатать все, начиная с этой подстроки?

const auto it = src.find('d'); // imagine this returns an iterator

std::cout << src.substr(std::distance(src.cbegin(), it));

Это можеттоже не будь, что хочешь. Следовательно, мы можем позволить std::string::find вернуть индекс, и вот мы:

const std::string extracted = src.substr(src.find('d'));

Если вы хотите работать с итераторами, используйте <algorithm>. Они позволяют вам как

auto it = std::find(src.cbegin(), src.cend(), 'd');

std::copy(it, src.cend(), std::ostream_iterator<char>(std::cout));
3 голосов
/ 23 октября 2019

Это потому, что std::string имеет два интерфейса:

  • Общий итератор интерфейс на основе всех контейнеров
  • std::string специфичный index интерфейс на основе

std::string::find является частью интерфейса index и поэтому возвращает индексы.

Используйте std::find для использованияобщий интерфейс на основе итератора.

Используйте std::vector<char>, если не хотите использовать интерфейс на основе индекса (не делайте этого).

...