سؤال

I couldn't find a better title for this issue, please update it if needed as per the below question.

Consider an iterator - iter, pointing to elements in a std::vector<int>. I'm inserting the value of *iter at the current iterator position using:

iter = target.insert(iter, *iter);

I understand that insert will return the iterator to the newly inserted element. Now I changed the above statement to:

iter = target.insert(iter, *iter++);

I knew that was going to behave awkwardly, and it resulted in Segmentation fault. What I can't understand is, how the above assignment is evaluated? I mean, to which element will iter point to after that assignment. As far as I understand, since I've used a post-increment operator, it should behave in similar way as the first statement, which I am inferring from the below sample assignment:

i = i++;

Since the above assignment doesn't affect the value of i, same should be true in case of *iter++.

What's the actual behaviour behind the scene?


This is the real code:

std::vector<int>::iterator begin = target.begin();

while (begin != target.end()) {
    if (*begin % 2 == 0) {
        begin = target.erase(begin);
    } else {
        begin = target.insert(begin, *begin); // I changed this line
        begin += 2;
    }
}

Basically the above code is removing the even element from vector, and duplicating the odd element.

Edit:

Ok, if I change the second line to ++begin, in addition to the previous change - it works in the same way as current code. So, I replaced two lines in the else block, with these lines:

begin = target.insert(begin, *begin++);
++begin;

So, it seems like it is assigning the iterator one past than that in the previous case.

So, this is what I understood from this behaviour:

  • *begin++ first de-references the begin to get the value at current location.
  • begin is post-incremented
  • The insert now inserts the de-referenced value before the iterator after the post-increment. So, it's not inserting before the original begin, rather, before the ++begin. And then returns the value ++begin, where it inserted.

Have I interpreted it correctly?

هل كانت مفيدة؟

المحلول

I couldn't quite understand your question, but to respond to the understanding you listed: Your understanding may be correct on a particular compiler/day/build. It is unspecified whether you will insert at begin or begin + 1 (which then results in the value returned from insert being one of two different possible values) because the compiler may evaluate the arguments to insert in any order it likes. Instead of trying to work out exactly what will happen, split the code into appropriate pieces the make it perfectly clear what you're trying to do and let the optimizer take care of things for you. Almost certainly the reason it core dumped is because when you increment by two you skip over end and never detect that you passed the end of the container.

I feel I should also point out that "luckily" there's a sequence point after the evaluation of function arguments, or begin = target.insert(begin, *begin++); would be undefined behavior with two writes to begin and no intervening sequence point (for example i = i++ is UB).

نصائح أخرى

AFAIK you construct target.insert(iter, *iter++) is not legal c++, as it leads to 'undefined behavior'. *iter++ is legal, and is evaluated left-to-right, but order in which agruments of a function call are evaluated is not specified. Writing such an expression is a programming error.

to be precise, your code

target.insert(iter, *iter++)

given aliases

std::vector<int>::iterator cur = iter;
std::vector<int>::iterator next = iter + 1;

can be evaluated in these 2 ways

targets.insert(next, *cur);
++iter;

or

targets.insert(cur, *cur);
++iter;

the exact version is a subject to compiler, os, other code etc and is generally not specified.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top