Ответ 1
Это в основном по историческим причинам, но не только.
Строковая библиотека и STL (которая представляет собой библиотеку контейнеров/алгоритмов, разработанную А. Степановым, которая в итоге стала частью стандартной библиотеки С++) были разработаны независимо, и они приняли различные соглашения.
Однако, поскольку они в конечном итоге оба конвертируются в стандартную библиотеку С++, С++ Standard делает попытку унифицировать эти синтаксические соглашения и позволяет использовать string
с алгоритмами STL, поэтому класс string
имеет функции-члены, такие как begin()
и end()
помимо других функций-членов, таких как substr()
.
Помимо обратной совместимости, в любом случае есть еще одна причина, по которой string
предоставляет функции-члены, такие как find()
: в отличие от контейнеров, которые предназначены для работы с универсальными алгоритмами, которые обеспечивают доступ к элементам или манипулируют ими, строки в основном рассматриваются как сами ценности, а не как совокупности значений (т.е. последовательности char
s). Таким образом, имеет смысл инкапсулировать алгоритмы, которые управляют значениями string
в функции-члены класса string
.
В своем дизайне стандартная библиотека С++ поддерживает оба этих представления string
s: как коллекции значений и самих значений.
UPDATE:
Бит вашего первого предложения "пока std::vector
и друзья его не имеют" не совсем правильно. По крайней мере, если вы расширяете диапазон друзей std::vector
до std::set
, std::multiset
, std::map
, std::multimap
, std::unordered_set
и std::unordered_map
(другими словами, в значительной степени для всех ассоциативных контейнеры в стандартной библиотеке С++).
У некоторых структур данных действительно есть версия функций некоторых общих STL-алгоритмов на их интерфейсе: это либо указывает на то, что эти алгоритмы имеют более эффективную реализацию, чем их общие экземпляры для этих конкретных структур данных (например, find()
) или что требуется специализированная реализация, поскольку общие алгоритмы вообще не могут применяться к этим структурам данных (например, std::remove()
, который изменяет значения в контейнере).