6

while programming I found out that my code was giving runtime error when I was using condition i < vec.size() - 1 but was working fine for i + 1< vec.size(). here vec was an empty std::vector.

//giving error
vector<int> vec;
for (int i = 0; i < vec.size() - 1; i++)
{
    //some code
}
//not giving error
vector<int> vec;
for (int i = 0; i + 1 < vec.size(); i++)
{
    //some code
}
Stack Danny
  • 7,754
  • 2
  • 26
  • 55
  • 1
    Your code iterates only over `size()` - 1 elements (meaning it misses the last element of the vector. ) Is this what you actually want, or did you actually intend to iterate over the whole vector? – Nikos C. Jun 26 '19 at 11:53

2 Answers2

13

The method std::vector::size returns a std::size_t which is unsigned. So if it is empty, you will get 0 - 1, but represented as an unsigned number, that will underflow and become 18446744073709551615 according to two's complement.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
  • 3
    note that it's not literally `0 - 1` but either `0u - 1`, `0ul - 1` or `0ull - 1` (implementation-dependant). – Stack Danny Jun 26 '19 at 11:51
  • 2
    @StackDanny This site needs a way to mark expressions as pure math to disambiguate from programming language expresions :) – eerorika Jun 26 '19 at 11:53
  • 2
    Note that whatever "two's complement" says doesn't affect what the result of `std::size_t(0) - 1`, because unsigned types don't have a sign representation. Standard specifies that the result is congruent modulo the maximum representable value + 1 (or 2**bits). -1 is congruent with X - 1 modulo X. – eerorika Jun 26 '19 at 11:59
  • Indeed, two's complement has nothing to do with this. – Lightness Races in Orbit Jun 26 '19 at 12:16
  • @eerorika that could be a nice feature-request on meta stackoverflow. – Stack Danny Jun 26 '19 at 12:17
4

Sidenote. It's not a good idea to compare signed and unsigned numbers. In C++20 we will have a new function std::ssize that returns a signed type. Then your example written as

 for (std::ptrdiff_t i = 0; i < std::ssize(vec) - 1; ++i)
 {
     //some code
 }

will be perfectly valid.

Note also how i is declared to be an std::ptrdiff_t (a signed integer type) to indicate array indexing.

Evg
  • 25,259
  • 5
  • 41
  • 83