-3

For example:

std::list <int> list1 = {1, 2, 3, 4, 5};
auto first = list1.begin();

std::cout <<  std::distance(--first, ++first);

The output is 0. Strange enough, if we change --first to first--, the output becomes 5 (although here it should be 0, as it returns first). What am I missing?

sadcat_1
  • 193
  • 10

2 Answers2

4

The order in which the arguments in a function call are evaluated is unspecified.

--first may execute first or ++first may execute first. If the former is the case, the decrement has undefined behavior, because decrementing a .begin() iterator is not allowed. Since one of the allowed execution orders has undefined behavior, your whole program has undefined behavior.

Using first-- instead doesn't change anything about this.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • Ok, my bad, but `distance(first, ++++first)` also outputs 0, where you would assuem it outputs 1 – sadcat_1 Feb 24 '22 at 08:04
  • 1
    @Suspicious_1 My old comment repeated since I deleted it wrongly: In `distance(first, ++++first)` if the left-hand argument evaluates first, because `std::distance` takes the iterators by-value, the result will be `2`. If the right-hand argument evaluates first the result will be `0`. So both `0` and `2` are possible outputs since C++17. – user17732522 Feb 24 '22 at 08:25
  • @Suspicious_1 However, before C++17 the argument evaluations were allowed to interleave, so then it could have been possible to generate `1` as well, if the left-hand side is evaluated in-between the two increment operator calls. Whether this is still possible or not since C++17 seems to have some disagreement, although it seems to me that it shouldn't, see [this question](https://stackoverflow.com/questions/71013035/function-argument-evaluation-and-side-effects). – user17732522 Feb 24 '22 at 08:27
1

Neither --first nor ++first is an rvalue. They are lvalues.

You are also not allowed to decrement the iterator returned by begin().

To get the distance between two rvalues, you could use std::prev and std::next:

auto second = std::next(list1.begin()); // to make std::prev(second) ok

std::cout <<  std::distance(std::prev(second), std::next(second));
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108