The compiler made an optimization when you are using *it in the function call. The following works:
#include <iostream>
#include <vector>
using namespace std;
int dist(size_t x, size_t y) {
cout<<"distance: "<<x<<" "<<y<<endl;
return y - x;
}
int main() {
// r is some Route, g is some Graph
vector<int> r = {1, 2, 3, 4};
int distance = 0;
for (auto it = r.begin(); it != r.end(); ) {
cout << "it: " << *it << endl;
int prev = *it;
++it;
int current = (it == r.end()) ? 0 : *it;
distance += dist(prev, current);
}
}
I am still digging the standard and trying to figure out why that optimization is allowed. Evaluation order doesn't really explain it.
========== Edit ===========================
I was wrong. Evaluation order is the cause of the problem. In this case, your ternary operator was evaluated in the correct order, but gcc is also free to move around the subexpression of the ternary operator. The assembly of your code looks like the following:
movq %rax, %rdi # tmp96,
call _ZN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEppEv #
leaq -32(%rbp), %rdx #, tmp97
movq %rdx, %rsi # tmp97,
movq %rax, %rdi # D.33388,
call _ZN9__gnu_cxxeqIPiSt6vectorIiSaIiEEEEbRKNS_17__normal_iteratorIT_T0_EESA_ #
# If the test succeeds, go to fetch the content of the iterator
# otherwise just set it to zero and proceed.
testb %al, %al # D.33389
je .L5 #,
movl $0, %ebx #, iftmp.2
jmp .L6 #
.L5:
leaq -64(%rbp), %rax #, tmp98
movq %rax, %rdi # tmp98,
# fetch the content of the iterator if we need it
call _ZNK9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEdeEv #
movl (%rax), %eax # *D.33393_16, D.33394
movslq %eax, %rbx # D.33394, iftmp.2
.L6:
leaq -64(%rbp), %rax #, tmp99
movq %rax, %rdi # tmp99,
# deference the iterator again. NOTE iterator here was NOT INTCREMENTED
call _ZNK9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEdeEv #
movl (%rax), %eax # *D.33395_19, D.33396
cltq
movq %rbx, %rsi # iftmp.2,
movq %rax, %rdi # D.33397,
call _Z4distmm #
addl %eax, -24(%rbp) # D.33398, distance
Pay attention to the evaluation of *it. In this case, the iterator was incremented if necessary, the ternary operator condition is evaluated, and then it is dereferenced.
============ Edit ===========
The order of evaluation in C++ for function parameters and its subexpressions are undefined. More information can be found on function parameter evaluation order. There is also a really nice artcle on the details of evaluation order written on cppreference