Is the following code defined behavior, I mean i-- when i is 0 will always be the biggest unsigned int representable by size_t, right ? so is this totally safe to use it in my code ?
size_t NPOS = -1;
for(size_t i = vec.size()-1; i!= NPOS; i--)
Is the following code defined behavior, I mean i-- when i is 0 will always be the biggest unsigned int representable by size_t, right ? so is this totally safe to use it in my code ?
size_t NPOS = -1;
for(size_t i = vec.size()-1; i!= NPOS; i--)
This is a classic scenario for using the fabulous goes-to operator:
for (size_t i = vec.size(); i --> 0; )
In class std::basic_string
static data member npos
is defined the following way
static const size_type npos = -1;
Take into account that the type of the return value of member function size()
is size_type
. So your code is valid
size_t NPOS = -1;
for(size_t i = vec.size()-1; i!= NPOS; i--)
provided that the value of expression vec.size()-1
can be stored in type size_t
so the more valid code will look as
for ( std::vector<T>::size_type i = vec.size()-1; i != std::vector<T>::npos; i-- )
Though I would write the loop the following way
for ( std::vector<T>::size_type i = vec.size(); i != 0; )
{
//...
// using expression vec[--i]
// or
// --i
// vec[i]
//...
}
Technically, it works, since the converion of -1
to an
unsigned type is guaranteed to result in the largest possible
value, as is decrementing from 0
. Still, it's not what
I would consider good practice. If you just want to iterate
over one vector in reverse:
for ( auto current = vec.rbegin(); current != vec.rend(); ++ current ) {
// Do something with *current
}
And if for some reason you do need the index:
int i = vec.size();
while ( i != 0 ) {
-- i;
// Do something with vec[i]
}
This loop is much cleaner, and avoids any issues with unsigned types wrapping (although if you need the index, that probably means you need it as an arithmetic value, so you should avoid unsigned types to begin with).
All of these will be the same value for a given integer type T
, signed or unsigned:
T a = -1;
T b = 0 - 1;
T c = 0; c = c - 1;
T d = 0; d --;
T e = 0; -- e;
assert(a == b);
assert(a == c);
assert(a == d);
assert(a == e);
That covers all of the usages you have in your snippet. The internal representation of the integer doesn't really matter. The fact that a signed -1 converts to the maximum value of a similar unsigned integer is interesting but not directly significant. The above is true else arithmetic stops working.