I find the behaviour of std::string::find
to be inconsistent with standard C++ containers.
E.g.
std::map<int, int> myMap = {{1, 2}};
auto it = myMap.find(10); // it == myMap.end()
But for a string,
std::string myStr = "hello";
auto it = myStr.find('!'); // it == std::string::npos
Why shouldn't the failed myStr.find('!')
return myStr.end()
instead of std::string::npos
?
Since the std::string
is somewhat special when compared with other containers, I am wondering whether there is some real reason behind this.
(Surprisingly, I couldn't find anyone questioning this anywhere).
To begin with, the std::string
interface is well known to be bloated and inconsistent, see Herb Sutter's Gotw84 on this topic. But nevertheless, there is a reasoning behind std::string::find
returning an index: std::string::substr
. This convenience member function operates on indices, e.g.
const std::string src = "abcdefghijk";
std::cout << src.substr(2, 5) << "\n";
You could implement substr
such that it accepts iterators into the string, but then we wouldn't need to wait long for loud complaints that std::string
is unusable and counterintuitive. So given that std::string::substr
accepts indices, how would you find the index of the first occurence of 'd'
in the above input string in order to print out everything starting from this substring?
const auto it = src.find('d'); // imagine this returns an iterator
std::cout << src.substr(std::distance(src.cbegin(), it));
This might also not be what you want. Hence we can let std::string::find
return an index, and here we are:
const std::string extracted = src.substr(src.find('d'));
If you want to work with iterators, use <algorithm>
. They allow you to the above as
auto it = std::find(src.cbegin(), src.cend(), 'd');
std::copy(it, src.cend(), std::ostream_iterator<char>(std::cout));
This is because std::string
have two interfaces:
std::string
specific index based interfacestd::string::find
is part of the index based interface, and therefore returns indices.
Use std::find
to use the general iterator based interface.
Use std::vector<char>
if you don't want the index based interface (don't do this).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With