Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does s.find return string::npos instead of s.length() on failure [closed]

Tags:

c++

string

find

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?

like image 634
uk4321 Avatar asked Nov 26 '13 20:11

uk4321


People also ask

What does NPOs mean in string?

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 ...

How to avoid error-1 when comparing idX and string NPOs?

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:

What is the NPOs value in C++?

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:

What is the value 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


2 Answers

Your question is actually twofold:

1) Why does std::string have it's own find function that returns a std::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());
like image 195
Zac Howland Avatar answered Oct 10 '22 01:10

Zac Howland


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.

like image 34
Dietmar Kühl Avatar answered Oct 10 '22 00:10

Dietmar Kühl