3

I have a question on c++ std iterators.

suppose iter is std::set<SomeType>::iterator type.

Is:

iter = ++iter 

the same as:

++iter 

or are they different?


edit:

I found a code std::set<UserDefinedClass*>::iterator being used that way. (pointer)
I wonder if that can cause the program I'm debugging malfunction.
I'm reading up the answers but it's hard to judge which answer is correct.

eugene
  • 39,839
  • 68
  • 255
  • 489
  • 2
    I think this is UB as the program is ill formed – iammilind Sep 01 '11 at 07:33
  • @iammilind: If you're worried about sequence points, remember that these are iterators, not primitive types. So `++` is an operator overload, so there is a sequence point here; hence the behaviour is well-defined. – Oliver Charlesworth Sep 01 '11 at 07:44
  • 1
    @iammilind: "Ill-formed" in C++ terminology designated a program that contains diagnosable errors, i.e. simply speaking a program that does not compile. UB on the other hand is usually a consequence of non-diagnosable errors. `iter = ++iter` in the above example is not ill-formed. – AnT stands with Russia Sep 01 '11 at 07:50

3 Answers3

7

There's no definitive answer to this question. The answer depends on the nature of std::set<SomeType>::iterator type. If it is a user-defined type (i.e. a class with overloaded operators), then the behavior of iter = ++iter is defined ans is indeed equivalent to a mere ++iter. However, if std::set<SomeType>::iterator is a built-in type, then iter = ++iter produces undefined behavior, since it modifies the same object twice in one expression without an intervening sequence point (violation of the requirements presented in 5/4 of the language standard).

So, theoretically in general case one should avoid doing something like that since in general case the behavior is undefined. In practice though std::set<SomeType>::iterator will normally be a user-defined type and iter = ++iter will work. Nevertheless this is not a reason to use such expressions in the code.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 1
    Is it possible to have `std::set::iterator` as a typedef for a builtin? My initial reaction is no as to make `*iter` work, then only type that would work would be an `X*` but the way that `++iter` and `--iter` would then work would imply that `set` would have to be implemented as an array, but then you couldn't erase an element from the middle of the `set` and maintain valid iterators to other elements. I may have missed something but I don't think that it's possible. – CB Bailey Sep 01 '11 at 07:47
  • 1
    @AndreyT: *if `std::set::iterator` is a built-in type, then `iter = ++iter` produces undefined behavior* [`[citation strongly needed]`](http://xkcd.com/285/) – user541686 Sep 01 '11 at 07:52
  • @Charles Bailey: I don't see how one can implement a compliant `std::set` with iterator being implementable through a built-in at the same time. This is why I said that in the real life it should "work". But in general case I woudn't discard the possibility. – AnT stands with Russia Sep 01 '11 at 07:53
  • @AndreyT: The edit is better, but I would still like to understand why assignment does not introduce a sequence point. How in the world could it be done in parallel with anything else? Aren't sequence points placed precisely to prevent parallel evaluations from happening? – user541686 Sep 01 '11 at 07:56
  • @Mehrdad: If you thing that the assignment introduces as sequence pointer, *you* have to provide the reference. You can't site where a sequence point *isn't* specified. – CB Bailey Sep 01 '11 at 07:58
  • 1
    @Mehrdad: I don't understand the "parallel" reference. Assignment does not introduce a sequence point because the standard doesn't say it introduces a sequence point. The fact that assignment changes its LHS is a *side-effect* of the assignment. The fact that `++` changes its argument is a *side-effect* of `++`. You have two competing side-effects in this case ("competing" = acting on the same object). The language does not care that these side-effects lead to the same end result. Every time you have multiple side-effects affecting the same object the behavior is undefined. – AnT stands with Russia Sep 01 '11 at 07:59
  • @AndreyT: +1 Yes, I now believe you're right. However, not arbitrarily: I believe there's a *reason* the standard doesn't say it requires a sequence point, and that it's due to parallelism -- I've updated my answer with a potential explanation of why this might be the case. – user541686 Sep 01 '11 at 08:05
  • Note that `iter = ++iter` is well defined in C++11. (because of `§1.9/15 ... "The value computations of the operands of an operator are sequenced before the value computation of the result of the operator." ...`) – Mankarse Sep 01 '11 at 17:08
  • @Mankarse: Yeah... Sequencing is considerably revamped in C++11. – AnT stands with Russia Sep 01 '11 at 17:32
2

Yes they are the same thing - but why do this?

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • 1
    No the former is undefined. The same variable is modified twice within the same sequence point. – ereOn Sep 01 '11 at 07:30
  • i'm debugging a code, the line looked suspicious and wanted to make sure if that's a valid code – eugene Sep 01 '11 at 07:31
  • 1
    @ereOn: What about the sequence point after the evaluation of the parameters for the function call `operator=`? Doesn't that separate the `++` from the `=` ? – CB Bailey Sep 01 '11 at 07:32
  • @Charles Bailey: Well, I might be wrong but I remember a question where the OP asked something quite similar and someone explained very well how this was undefined. I just can't get my hands on it. Perhaps it was about `i = i++` and not `i = ++i` (not sure if it changes something). Was that a rhetorical question or are you sure it works ? – ereOn Sep 01 '11 at 07:36
  • @ereOn: Yes, it was probably `i++` and not `++i`. – user541686 Sep 01 '11 at 07:37
  • @ereOn: I'm not 100% certain, but I can't think of any valid type that `std::set::iterator` could be that wouldn't require `=` to be provided by an overloaded operator function. If it is a function then I'm fairly sure that I'm correct as any read or write performed by `++` would have to be separated from any read or write on the same object caused by `=` by at least one sequence point. – CB Bailey Sep 01 '11 at 07:39
  • @Charles Bailey: It seems [you are right](http://stackoverflow.com/questions/3914315/difference-between-i-i-and-i-closed). My bad. Thank you for pointing out my mistake. It's always good to learn. – ereOn Sep 01 '11 at 07:43
  • @ereOn: Something tells me the answer you linked to might be wrong. Everywhere else on the 'net, the example they cite is `i = i++`, not `i = ++i`. But I could still be wrong, as I have not seen the standard itself. – user541686 Sep 01 '11 at 07:47
  • @Mehrdad: I was more linking to the whole question, with all its answers and comments, not particularly to the most upvoted answer. Anyway, I haven't seen the standard either so I can't tell for sure. – ereOn Sep 01 '11 at 07:55
  • @Mehrdad: What do you believe is the fundamental difference between `i = i++` and `i = ++i`, w.r.t. UB? (Obviously, I'm not talking about the result if there is no UB which is different between the two expressions.) If `=` is a function call then there's a sequence point in both cases, if `=` is the built-in assignment operator then there's two writes with no intervening sequence point in both cases. – CB Bailey Sep 01 '11 at 07:56
  • @Charles: Never mind, I'm convinced that you're correct. +1 for Ed. – user541686 Sep 01 '11 at 08:07
  • @AlfPSteinbach: Was that -1 at the answer? If so, are you on the side of UB or did you have other reasoning? – CB Bailey Sep 01 '11 at 08:10
  • @Charles: yes, I downvoted the answer. Formally the assignment expression can have UB for certain set element types, e.g. a perverse implementation of `std::set` could have raw pointers as iterators. And in practice the question is not about just `std::set`, and then one must consider that e.g. some early implementations of `std::vector` used raw pointers as iterators. With raw pointer iterators, as it can be in the formal and as it has been in practice, the assignment is UB. – Cheers and hth. - Alf Sep 01 '11 at 08:36
0

Yes, same thing. A simpler case, same thing:

int i = 10;   //i = 10
int j = i++;  //j = 10
int k = ++i;  //k = 12

However

i = ++i; 

is unnecessary as it increments i and then assigns i to i

edvaldig
  • 2,301
  • 16
  • 17
  • 3
    It is not only unnecessary, it is *not allowed* for an int as it changes i's value twice without an intervening sequence point. The question likely uses overloaded operators (function calls) so the result there is different (and defined). – Bo Persson Sep 01 '11 at 07:52
  • 1
    Not going to downvote, but I agree with @Alf. "Proof by example" doesn't work in the case of undefined behavior -- by definition, U.B. can include "reasonable" behavior. – user541686 Sep 01 '11 at 08:09