4

Here's evidence that it is:

inline
constexpr std::size_t prev(std::size_t i) {
    --i;
    return i;
}

int main() {
    static const std::size_t i = 0;
    static_assert(prev(i) == std::size_t(-1), "Decrementing should give     std::size_t(-1)");    
    return 0;
}

That compiles happily with -std=c++14.

I came upon this because I had a loop indexing over a std::vector and wanted to loop backward, so I changed it to

for (std::size_t i = std::min(idx, v.size() - 1); i != std::size_t(-1); --i) { ... }

Now, I realize I could use std::vector::reverse_iterator, but my real question now is, is the behavior I'm expecting well-defined?

Ben
  • 9,184
  • 1
  • 43
  • 56

2 Answers2

6

Yes

size_t is an unspecified unsigned integer.

All unsigned integers in C++ are modelled as elements of the ring of integers modulo 2n for some number n specific to that unsigned integer type.

When you convert a signed integer to an unsigned integer you get the value in the ring of integers modulo 2n for the constant n for that unsigned type. For -1, this is 2n-1.

When you decrement 0 as an unsigned integer type, you get 2n-1.

These two values are the same.

See [basic.fundamental] 3.9.1/4 from the C++ standard:

Unsigned integers shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.

(Quote taken from N3690, a recent draft standard, but the truth it represents isn't going to change any time soon; the paragraph number might.)

Finding quotes on how conversion from a signed integer works would involve more standard chasing; but it ends up being what you want.

Community
  • 1
  • 1
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
5

Yes, this behavior is guaranteed.

std::size_t is an unsigned integer type. Arithmetic on unsigned integers always has well defined semantics:

Unsigned integer arithmetic is always performed modulo 2n where n is the number of bits in that particular integer.

Specifically considering the built-in pre-decrement and post-decrement operators:

[T]he expression --x is exactly equivalent to x -= 1. ...
[T]he expression x-- modifies the value of its operand as if by evaluating x -= 1

So the decrement operator does perform an arithmetic operation.

Justin
  • 24,288
  • 12
  • 92
  • 142
  • You get the green check because of the details on increment and decrement operators. – Ben Aug 02 '18 at 13:59