Topic: is string::npos defined to be -1?


Author: Pete Becker <petebecker@acm.org>
Date: 2000/04/26
Raw View
Rob Stewart wrote:
>
> So, the one remaining problem in the expression npos + 1 is the
> integral promotion should the type of npos be an unsigned type
> smaller than unsigned int, right?
>
> Therefore, the OP said "s.erase(s.find_last_not_of(t) + 1)" was
> safe, but that involves the potential for integral promotion.
> Therefore, if it was "s.erase(s.find_last_not_of(t) + 1u)" it
> would be safe, right?

This version of basic_string::erase takes a size_type as its argument,
so the possible promotions don't matter -- the conversion back to
size_type for the call masks any differences. There's no need to try to
outguess the type system here.

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Contibuting Editor, C/C++ Users Journal (http://www.cuj.com)
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Bill Wade" <bill.wade@stoner.com>
Date: 2000/04/26
Raw View
Rob Stewart <donotspamme@giage.com> wrote in message
news:39049205.94E62865@giage.com...

> Therefore, the OP said "s.erase(s.find_last_not_of(t) + 1)" was
> safe, but that involves the potential for integral promotion.

I will need to contradict what I probably said much earlier in the thread.
Since the first argument to s.erase() is a size_type argument, the integral
promotion does not hurt.  The integer gets converted back to the shorter
unsigned type using the standard integral conversion, and erase() just sees
zero.

What is not safe, is a test similar to
   if(s.find_last_not_of(t)+1 == 0)

Note that on platforms where short is smaller than int the following holds:
  typedef unsigned short us;
  1+us(-1) != 0         // Similar to the 'if' above.
  us(1+us(-1)) == 0  // Similar to the call to erase
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 2000/04/26
Raw View
Rob Stewart wrote:
>
> James Kuyper wrote:
> >
> > Rob Stewart wrote:
> > >
> > > James Kuyper wrote:
> > ....
> > > > For a general Allocator, the only requirement is that size_type must be
> > > > a signed integral type. As far as I can tell, even 'unsigned char' would
> > >   ^^^^^^^^
> > >
> > > You no doubt meant, "an unsigned" there.
> >
> > Correct. Sorry!
> >
> > > > be legal.
> > >
> > > Where is that requirement?
> >
> > Table 32. I left out one detail. size_type must be also be "a type that
> > can represent the size of the largest object in the allocation model."
> > Therefore, an allocator that used 'unsigned char' as its size_type could
> > allocate no more than UCHAR_MAX bytes.
>
> So, the one remaining problem in the expression npos + 1 is the
> integral promotion should the type of npos be an unsigned type
> smaller than unsigned int, right?
>
> Therefore, the OP said "s.erase(s.find_last_not_of(t) + 1)" was
> safe, but that involves the potential for integral promotion.
> Therefore, if it was "s.erase(s.find_last_not_of(t) + 1u)" it
> would be safe, right?

Assume that size_type is 'unsigned short', and that USHORT_MAX <
INT_MAX. Then, the first step in the "usual arithmetic conversions that
applies is:
"Otherwise, the integral promotions (4.5) shall be performed on both
operands." Since USHORT_MAX < INT_MAX, that means that the result
returned by find_last_not_of() is converted to an 'int'. If that value
was (unsigned short)(-1), it will be USHORT_MAX.

Now, with "+1", the 1 has type 'int', and the sum has a value of
USHORT_MAX+1 and a type of 'int'.
With "+1u", the '1u' has a type of 'unsigned', and therefore the value
of USHORT_MAX gets converted, unchanged, to 'unsigned' to match. The
result is a value of USHORT_MAX+1, with type 'unsigned'.

In both cases, the result is then converted back to unsigned short, as
that is the parameter type that is taken by erase(). The result is 0. So
both expressions produce the desired result.

While the OP was talking about this case, the message I was responding
to was by the one in which you talked about Bill Wade's claim that

 (npos+1) != size_type(npos+1)

In that case, the LHS of the comparison has a value of USHORT_MAX+1, and
a type of 'int'. The RHS has a value of 0 and type of unsigned short.
The right hand side will be converted to 'int', and the comparison would
return true, as Bill Wade said.
If the '1's are replace by '1u', then the LHS has a value of
USHORT_MAX+1 and a type of 'unsigned'. The RHS has a value of 0 and a
type of 'unsigned'.  Therefore, no conversions are needed to perform the
comparison, which still returns true.
Either way, the results are counterintuitive.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Rob Stewart <donotspamme@giage.com>
Date: 2000/04/22
Raw View
James Kuyper wrote:
>
> Rob Stewart wrote:
> >
> > Bill Wade wrote:
> ....
> > But std::allocator<T>::size_type is required to be size_t and
> > we're discussing std::basic_string.
>
> The Allocator template argument of std::basic_string<charT,Allocator> is
> not required to be std::allocator<T>, though that is the default
> argument.

I acknowledged that very issue as you quoted below.

> ....
> > > typedef unsigned short size_type;
> > > const size_type npos = -1;
> > >
> > > Now
> > >   (npos+1) != size_type(npos + 1)
> > > on systems where int is bigger than short.
> >
> > You can parameterizing basic_string with another allocator, but
> > I'm not sure it can used signed types for size_type.  The
>
> Why is that relevant? 'unsigned short', as its name implies, isn't a
> signed type. The signed type 'int' indirectly causes problems for the
> above expression, if INT_MAX is greater than or equal to USHORT_MAX, due
> to the default promotions.

Of course.  I wasn't thinking of the integral promotion for the
expression.  If "1" were replaced with "1u", and if, indeed,
allocators must typedef size_type to unsigned integral types, it
would work, but a compiler is likely to warn about loss of
information.

> > requirements for allocators are pretty sparse.  Hopefully someone
> > with more knowledge will weigh in on this.
>
> For a general Allocator, the only requirement is that size_type must be
> a signed integral type. As far as I can tell, even 'unsigned char' would
  ^^^^^^^^

You no doubt meant, "an unsigned" there.

> be legal.

Where is that requirement?

--
Robert Stewart     |  rob-at-giage-dot-com
Software Engineer  |  using std::disclaimer;
Giage, Ltd.        |  http://www.giage.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 2000/04/24
Raw View
Rob Stewart wrote:
>
> James Kuyper wrote:
....
> > For a general Allocator, the only requirement is that size_type must be
> > a signed integral type. As far as I can tell, even 'unsigned char' would
>   ^^^^^^^^
>
> You no doubt meant, "an unsigned" there.

Correct. Sorry!

> > be legal.
>
> Where is that requirement?

Table 32. I left out one detail. size_type must be also be "a type that
can represent the size of the largest object in the allocation model."
Therefore, an allocator that used 'unsigned char' as its size_type could
allocate no more than UCHAR_MAX bytes.

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: 2000/04/24
Raw View
On 22 Apr 2000 13:38:58 -0400, Rob Stewart <donotspamme@giage.com>
wrote:

> James Kuyper wrote:
> > For a general Allocator, the only requirement is that size_type must
be
> > a signed integral type. As far as I can tell, even 'unsigned char'
would
>   ^^^^^^^^
>
> You no doubt meant, "an unsigned" there.
>
> > be legal.
>
> Where is that requirement?

Allocator:  Table 32
String:     21.3/6
Container:  Table 65

Unfortunately, there is no requirement for Container size_type to
match its Allocator size_type.  There is for string.

John

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Rob Stewart <donotspamme@giage.com>
Date: 2000/04/25
Raw View
James Kuyper wrote:
>
> Rob Stewart wrote:
> >
> > James Kuyper wrote:
> ....
> > > For a general Allocator, the only requirement is that size_type must be
> > > a signed integral type. As far as I can tell, even 'unsigned char' would
> >   ^^^^^^^^
> >
> > You no doubt meant, "an unsigned" there.
>
> Correct. Sorry!
>
> > > be legal.
> >
> > Where is that requirement?
>
> Table 32. I left out one detail. size_type must be also be "a type that
> can represent the size of the largest object in the allocation model."
> Therefore, an allocator that used 'unsigned char' as its size_type could
> allocate no more than UCHAR_MAX bytes.

So, the one remaining problem in the expression npos + 1 is the
integral promotion should the type of npos be an unsigned type
smaller than unsigned int, right?

Therefore, the OP said "s.erase(s.find_last_not_of(t) + 1)" was
safe, but that involves the potential for integral promotion.
Therefore, if it was "s.erase(s.find_last_not_of(t) + 1u)" it
would be safe, right?

--
Robert Stewart     |  rob-at-giage-dot-com
Software Engineer  |  using std::disclaimer;
Giage, Ltd.        |  http://www.giage.com

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Rob Stewart <donotspamme@giage.com>
Date: 2000/04/15
Raw View
Bill Wade wrote:
>
> Fernando Luis Cacciola Carballal <fcacciola@fibertel.com.ar> wrote in
> message news:8cva8u$12o3@mail05.knox.edu...
> > I claimed that the call   s.erase ( s.find_last_not_of ( t ) + 1 ) is always
> > safe since
>
> No.
>
> > basic_string::npos is defined to be 'the largest value of type
> > size_t',
>
> Yes (well strictly speaking I think that should be size_type).

But std::allocator<T>::size_type is required to be size_t and
we're discussing std::basic_string.

> > which implies that npos+1 is guaranteed to be 0.
>
> No.  Consider:
>
> typedef unsigned short size_type;
> const size_type npos = -1;
>
> Now
>   (npos+1) != size_type(npos + 1)
> on systems where int is bigger than short.

You can parameterizing basic_string with another allocator, but
I'm not sure it can used signed types for size_type.  The
requirements for allocators are pretty sparse.  Hopefully someone
with more knowledge will weigh in on this.

--
Robert Stewart     |  rob-at-giage-dot-com
Software Engineer  |  using std::disclaimer;
Giage, Ltd.        |  http://www.giage.com

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 2000/04/16
Raw View
Rob Stewart wrote:
>
> Bill Wade wrote:
....
> But std::allocator<T>::size_type is required to be size_t and
> we're discussing std::basic_string.

The Allocator template argument of std::basic_string<charT,Allocator> is
not required to be std::allocator<T>, though that is the default
argument.

....
> > typedef unsigned short size_type;
> > const size_type npos = -1;
> >
> > Now
> >   (npos+1) != size_type(npos + 1)
> > on systems where int is bigger than short.
>
> You can parameterizing basic_string with another allocator, but
> I'm not sure it can used signed types for size_type.  The

Why is that relevant? 'unsigned short', as its name implies, isn't a
signed type. The signed type 'int' indirectly causes problems for the
above expression, if INT_MAX is greater than or equal to USHORT_MAX, due
to the default promotions.

> requirements for allocators are pretty sparse.  Hopefully someone
> with more knowledge will weigh in on this.

For a general Allocator, the only requirement is that size_type must be
a signed integral type. As far as I can tell, even 'unsigned char' would
be legal.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Bill Wade" <bill.wade@stoner.com>
Date: 2000/04/13
Raw View

Fernando Luis Cacciola Carballal <fcacciola@fibertel.com.ar> wrote in
message news:8cva8u$12o3@mail05.knox.edu...
> I claimed that the call   s.erase ( s.find_last_not_of ( t ) + 1 ) is always
> safe since

No.

> basic_string::npos is defined to be 'the largest value of type
> size_t',

Yes (well strictly speaking I think that should be size_type).

> which implies that npos+1 is guaranteed to be 0.

No.  Consider:

typedef unsigned short size_type;
const size_type npos = -1;

Now
  (npos+1) != size_type(npos + 1)
on systems where int is bigger than short.




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]