string::npos + 1 ???

D

Derek

A common technique for trimming leading and trailing spaces
from std::string is the following:

string s(" blah blah blah ");

const char* ws= " \t\r";
string::size_type not_white;

// trim leading whitespace
not_white = s.find_first_not_of(ws);
s.erase(0, not_white);

// trim trailing space
not_white = s.find_last_not_of(ws);
s.erase(not_white+1); /*** Is this safe? ***/
// ^^^^^^^^^^^

My question is about the underlined not_white+1. What if
the find_last_not_of call returns string::npos, as would
happen if s was a blank string. It seems to work with
all of my compilers, but it seems dubious to increment
string::npos.
 
K

Kevin Goodsell

Derek said:
A common technique for trimming leading and trailing spaces
from std::string is the following:

string s(" blah blah blah ");

const char* ws= " \t\r";
string::size_type not_white;

// trim leading whitespace
not_white = s.find_first_not_of(ws);
s.erase(0, not_white);

// trim trailing space
not_white = s.find_last_not_of(ws);
s.erase(not_white+1); /*** Is this safe? ***/
// ^^^^^^^^^^^

My question is about the underlined not_white+1. What if
the find_last_not_of call returns string::npos, as would
happen if s was a blank string. It seems to work with
all of my compilers, but it seems dubious to increment
string::npos.

npos is defined as -1 converted to string::size_type, which is an
unsigned integral type. As per the rules of unsigned types, -1 becomes
the largest representable value. Adding 1 causes this value to wrap
around to 0. Therefore, the result will be equivalent to

s.erase(0);

As far as I can tell, there's nothing wrong with this. It should make
's' empty (if it isn't already -- in your example it should already be).
This seems to give the expected result in your code, but it may be a bit
confusing. It may not be immediately obvious to someone reading the code
that it is correctly handling this case, and therefore it might be
worthwhile to make handling of it explicit. But that's your call.

-Kevin
 
S

Siemel Naran

A common technique for trimming leading and trailing spaces
from std::string is the following:

string s(" blah blah blah ");

const char* ws= " \t\r";
string::size_type not_white;

// trim leading whitespace
not_white = s.find_first_not_of(ws);
s.erase(0, not_white);

// trim trailing space
not_white = s.find_last_not_of(ws);
s.erase(not_white+1); /*** Is this safe? ***/
// ^^^^^^^^^^^

What happens here?

std::string s;
trimboth(s);
 
M

Michiel Salters

Siemel Naran said:
What happens here?

std::string s;
trimboth(s);

Nothing?
The typical implementation error for trimboth shows up when trimming
" ", as the search from the front crosses the search from the end.
In the empty string, the front and the back are equal and the search
doesn't cross. Therefore you don't get negative distances to erase,
you get a zero distance.

The implementation above is correct, even with the " " testcase, as the
second trim works on the trimmed interim result "".

Regards,
Michiel Salters
 
D

Derek

Siemel said:
What happens here?

std::string s;
trimboth(s);

It works as expected with the latest GCC and VC7.1, even
when s is blank. When the string is blank, the case I'm
concerned about, trimming the left side looks like this:

not_white = s.find_first_of(ws); // returns npos
s.erase(0, not_white); // fine

And the left side:

not_white = s.find_last_not_of(ws); // returns npos
s.erase(npos + 1);

As Kevin pointed out, the last line amounts to

s.erase(0)

which is fine. Of course if the string was not blank
this sequence would have produced the expected trimmed
string.
 
J

Jorge Rivera

Derek said:
It works as expected with the latest GCC and VC7.1, even
when s is blank. When the string is blank, the case I'm
concerned about, trimming the left side looks like this:

The fact that it works with current versions doesn't mean all that much
to me in this case.

If I understood the problem, the question is what happens
std::string::npos is not equal to -1, as is the case in the compilers
you mentioned?

Is there a guarantee that npos == -1?, or is this just pure luck????
 
K

Kevin Goodsell

Jorge said:
If I understood the problem, the question is what happens
std::string::npos is not equal to -1, as is the case in the compilers
you mentioned?

Is there a guarantee that npos == -1?, or is this just pure luck????

It is required that basic_string::npos be the largest representable
value for basic_string::size_type. In other words, it must be equal to
static_cast<basic_string::size_type>(-1).

-Kevin
 
M

Michiel Salters

Jorge Rivera said:
Is there a guarantee that npos == -1?, or is this just pure luck????


If it is not, the compiler would have a (serious) bug. That is no
guarantee, if you read your EULA. However, this is too easy to spot
and fix, so compiler vendors in practice get this right.

( technically, it's not -1 but (size_type) -1 which is positive )
 
J

Jorge Rivera

It is required that basic_string::npos be the largest representable
value for basic_string::size_type. In other words, it must be equal to
static_cast<basic_string::size_type>(-1).

-Kevin

Thanks,

JLR
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top