NihVo
NihVo

Reputation: 13

Why "if (unsigned int == string::npos )" CAN be true?

Let me start by saying: I'm sorry if this was explained, I tried reading about it and searching for answer but I didn't find one that answered this specific question.

So I'm writing beginner's level code in C++ and I wrote a very simple function that returns index of the next found character that isn't space. It was inspired by the method string.find(). If the function doesn't find anything it returns string::npos.

int findChar (const string &line, const int startPos){
    for (unsigned int i= startPos; i < line.length(); i++){
        if ( line[i] != ' ') return i;
    }
    return string::npos;
}

Now, because I'm working on strings and indices, I thought of using a unsigned int.

unsigned int where;
where = findChar(line, 0);

And because "where" is an unsigned int I thought comparison of "where == string::npos" is a bad idea because string::npos is initialized with -1, and unsigned int can't be equal to -1. But if the function doesn't find anything and it returns string::npos the condition can be true, the program recognizes that "unsigned int where" is string::npos, but when I try to print "where" out, it prints out as biggest number unsigned int can hold.

So my question is why, or how, the program can recognize unsigned int to be equal to string::npos, even though technically string::npos is initialized with value of -1.

I'm trying to learn so if you can point me to some reading material that also answers this I'd be grateful.

Upvotes: 0

Views: 854

Answers (2)

M.M
M.M

Reputation: 141648

string::npos is a large positive number .

To avoid these issues, your function's return type should match the type of the value you are returning, e.g.:

  • return string::size_type instead of int, or:
  • return some other failure sentinel such as -1 in the first code.

The way you have it now, there can always be a clash when the "adjusted" value to fit in the return type happens to be the same as a valid return value.

Although npos might be initialized with -1 in an implementation header, that doesn't mean its value is -1. The initializer is converted to the type of the object being initialized, which is string::size_type, guaranteed to be an unsigned type. The result of this conversion is a large positive value.


NB. Your code will break miserably if called on a string longer than UINT_MAX characters, since the i loop never ends. The i should also be string::size_type rather than int; and similar considerations apply to the startPos parameter.

Upvotes: 1

tadman
tadman

Reputation: 211700

If you read the documentation:

Although the definition uses -1, size_type is an unsigned integer type, and the value of npos is the largest positive value it can hold, due to signed-to-unsigned implicit conversion. This is a portable way to specify the largest value of any unsigned type.

Note: std::string::npos is of type size_t. Using anything else may be undefined behaviour and is not advised.

Upvotes: 3

Related Questions