|with *(iterator++) you should first increment the iterator THEN dereference it.|
The return value of post-increment is the nameless copy
of the non-incremented argument. That is what is returned from the parenthesized expression, regardless of when the increment occurs, and that is what operator* gets to work with.
However, there's another thing I'd like to point out.
|I thought that when an expression contains brackets, whatever is inside those brackets should be evaluated first.|
No, it only means it is *parsed* first. Precedence is not evaluation order, precedence is grammar. It is the set of rules by which an expression is parsed into the tree form
Your expression is parsed into this tree:
iterator ---> op++(post) ---> op* ,- store
,- increment op(=) ---> (discard)
iterator2 ---> op++(post) ---> op*
The compiler has (almost) free reign on how to evaluate this tree. Depth-first, breadth-first, top first, bottom first, or in any other manner. Your compiler apparently went (how did it "tell" you anyway?) copy, copy, op*, op*, op=, store, top increment, bottom increment. Another compiler could go top copy, top op*, top increment, bottom copy, bottom op*, bottom increment, op=, store. Another compiler could go top copy, bottom copy, bottom op*, top increment, top op*, op=, store, bottom increment. It could even interleave the individual CPU instructions working on unrelated data, to improve pipelining (but only if the arguments are scalars, e.g. typedefed pointers. There is much less leeway when those operators are user-defined functions)