I recently was annoyed to find that string::find
returns string::npos
when the needle isn't found in the haystack. This makes the following seemingly-elegant code compile but throw an out-of-range exception:
s.erase(s.find('#')); // erase everything after a # if one exists
If find
returned s.length()
on failure, it would work fine. Instead you have to do
auto pos = s.find('#');
if (pos != s.npos)
s.erase(pos);
This is also inconsistent with std::find
which returns the end iterator if the item isn't found.
I know the standard people are pretty smart so I believe they didn't just come up with this out of nowhere. It must give some elegance somewhere else that I'm not seeing. What is the good reason for this?
What is string::npos: It is a constant static member value with the highest possible value for an element of type size_t. It actually means until the end of the string. It is used as the value for a length parameter in the string ’s member functions. As a return value, it is usually used to indicate ...
idx == std::string::npos might yield false if idx has the value -1and idx and string::nposhave different types: std::string s; ... int idx = s.find("not found"); // assume it returns npos if (idx == std::string::npos) { // ERROR: comparison might not work ... One way to avoid this error is to check whether the search fails directly:
Where, npos is constant static value with the highest possible value for an element of type size_t and it is defined with -1. Program 1: Below is the C++ program to illustrate the use of string::npos:
1 Value of string::npos is 18446744073709551615. Its a value returned if there is no string found. Share Improve this answer Follow answered Apr 20 '20 at 17:01
Your question is actually twofold:
1) Why does
std::string
have it's ownfind
function that returns astd::size_t
value instead of an iterator?
This is largely due to the fact that std::string
was developed separately from much of the rest of the standard library. It is only in recent standards that it has been embraced by other templates (e.g. iostream). So when it was added to the standard, it had some functions added to it, but it's orginal functionality was left pretty much as-is (the exception being the common implemention of copy-on-write, which was forbidden in the C++11 standard). It was left this way largely for backward-compatibility.
Per your question about why it was that way to begin with: The original string.h
was a very thin wrapper around several C string functions. It was not at all uncommon to see strlen
used as a return value for length()
, or strcpy
used in the copy constructor. There was no requirement forcing the use of these functions, so eventually implementers started doing some interesting things (e.g. copy-on-write, non-contiguous memory blocks), but they left the interface the same to preserve backwards-compatibility. While functions have been added to it, no public functions have been removed from the interface. So you can trace the design decisions for using a pointer and length for function parameters back to the days when it was merely a wrapper around the C functions.
2) How can you write an erase sequence on a string without having to check the return value?
This can be done simply by using the find-erase idiom, but not using std::string
's find function:
s.erase(std::find(s.begin(), s.end(), '#'), s.end());
Using std::string::npos
makes the result a constant expression unlike std::string::length()
. Since npos
isn't suitable as an iterator anyway there is value in having a constant expression, e.g., it can be used as default for parameters taking a std::string::size_type
.
Another reason is that the basic interface for std::basic_string
was put together before STL was added to the C++ standard library (well, at least, there is a part of the interface which existed then). The original interface was basically an immutable string and I think it didn't support any mutation of the string itself.
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