7

Examples showing how to iterate over a std::map are often like that:

MapType::const_iterator end = data.end(); 
for (MapType::const_iterator it = data.begin(); it != end; ++it)

i.e. it uses ++it instead of it++. Is there any reason why? Could there be any problem if I use it++ instead?

Mat
  • 202,337
  • 40
  • 393
  • 406
laurent
  • 88,262
  • 77
  • 290
  • 428
  • Have a look at [this][1]. [1]: http://stackoverflow.com/questions/24853/c-what-is-the-difference-between-i-and-i – sergio Aug 03 '11 at 13:13
  • 7
    If you code in C++ for any length of time, `++it` will provide a significant boost to efficiency. Not in your code, but in time spent explaining to people why you didn't do `++it` in the first place. Since it really does not matter in the slightest, you might as well do it the way that won't lead to arguments. – Dennis Zickefoose Aug 03 '11 at 14:13
  • @Dennis: It doesn't matter *much* and very often won't be measurable, but in tight loops, it can make a difference. – Christopher Creutzig Aug 03 '11 at 14:22
  • @Christopher: People say that, but nobody ever shows an example of when. Every test I have ever run has resulted in the resulting code being so nearly identical that even in "tight loops" it couldn't possibly be worth worrying over. The only exception has been when the increment operators were sufficiently complex that they could not be inlined [and thus the extraneous temporary not removed]. – Dennis Zickefoose Aug 03 '11 at 14:36
  • @Dennis: I should have qualified that more, yes. I was talking about the unusual situation of complicated iterators. – Christopher Creutzig Aug 04 '11 at 08:00

6 Answers6

20

it++ returns a copy of the previous iterator. Since this iterator is not used, this is wasteful. ++it returns a reference to the incremented iterator, avoiding the copy.

Please see Question 13.15 for a fuller explanation.

Dark Falcon
  • 43,592
  • 5
  • 83
  • 98
  • 4
    It's hardly going to matter. The issue is purely of style. – Cat Plus Plus Aug 03 '11 at 13:13
  • 1
    @Dark - Since it is not used, the compiler is likely to notice this and optimize the copy away. – Bo Persson Aug 03 '11 at 14:40
  • 2
    I am aware of that. Obviously the compiler is not required to do so, however. – Dark Falcon Aug 03 '11 at 14:46
  • I personally find pre-increment reads better. Read the '++' as "increment", and it becomes "increment it" in your head, instead of "it increment" – Matt Greer Aug 03 '11 at 20:07
  • 1
    I wouldn't say it's a matter of style. Pre-increment says, "Increment." Post-increment says, "Increment, but give me the original value back so I can do something with it." If you're not doing something with the original value, then post-increment doesn't express your intent as clearly. – Ben Aug 04 '11 at 19:23
  • Purely a matter of style. To me, Pre-increment says "Preemptively get me the incremented value of the variable because I need to do something with that right now in this line, because the next line will be too late". Operator overloading aside, Post-increment is just a nice readable synonym for "+=1" - that is, an assignment, and the variable on the left is correctly the l-value. Programmers read in simple present tense verbs: `a=3;` -> "a becomes 3." `a++;` -> "a increments." Unfortunately, as it's "just style to so many", we must always have a comment explaining *why* it matters, if it does. – Dewi Morgan Jan 29 '15 at 22:39
11

Putting it to the test, I made three source files:

#include <map>

struct Foo { int a; double b; char c; };

typedef std::map<int, Foo> FMap;

### File 1 only ###

void Set(FMap & m, const Foo & f)
{
  for (FMap::iterator it = m.begin(), end = m.end(); it != end; ++it)
    it->second = f;
}

### File 2 only ###

void Set(FMap & m, const Foo & f)
{
  for (FMap::iterator it = m.begin(); it != m.end(); ++it)
    it->second = f;
}

### File 3 only ###

void Set(FMap & m, const Foo & f)
{
  for (FMap::iterator it = m.begin(); it != m.end(); it++)
    it->second = f;
}

### end ###

After compiling with g++ -S -O3, GCC 4.6.1, I find that version 2 and 3 produce identical assembly, and version 1 differs only in one instruction, cmpl %eax, %esi vs cmpl %esi, %eax.

So, take your pick and use whatever suits your style. Prefix increment ++it is probably best because it expresses your requirements most accurately, but don't get hung up about it.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    Nice display of optimization, but that can only work for sufficiently simple and inlined `operator++`. Good to see g++ can do it for `std::map`. – Christopher Creutzig Aug 03 '11 at 14:26
  • 1
    @Christopher: Yeah, and you should definitely always use `++it` when that's what you mean. I just felt like providing some hard comparison on the true impact of two oft-advertised points (hoisting the end out and using prefix increment). – Kerrek SB Aug 03 '11 at 14:29
7

There’s a slight performance advantage in using pre-increment operators versus post-increment operators. In setting up loops that use iterators, you should opt to use pre-increments:

for (list<string>::const_iterator it = tokens.begin();
    it != tokens.end();
    ++it) { // Don't use it++
    ...
}

The reason comes to light when you think about how both operators would typically be implemented.The pre-increment is quite straightforward. However, in order for post-increment to work, you need to first make a copy of the object, do the actual increment on the original object and then return the copy:

class MyInteger {
private:
    int m_nValue;

public:
    MyInteger(int i) {
        m_nValue = i;
    }

    // Pre-increment
    const MyInteger &operator++() {
        ++m_nValue;
        return *this;
    }

    // Post-increment
    MyInteger operator++(int) {
        MyInteger clone = *this; // Copy operation 1
        ++m_nValue;
        return clone; // Copy operation 2
    }
}

As you can see, the post-increment implementation involves two extra copy operations. This can be quite expensive if the object in question is bulky. Having said that, some compilers may be smart enough to get away with a single copy operation, through optimization. The point is that a post-increment will typically involve more work than a pre-increment and therefore it’s wise to get used to putting your “++”s before your iterators rather than after.

(1) Credit to linked website.

6

At logical point of view - it's the same and it doesn't matter here.

Why the prefix one is used - because it's faster - it changes the iterator and returns its value, while the postfix creates temp object, increments the current iterator and then returns the temp object (copy of the same iterator, before the incrementing ). As no one watches this temp object here (the return value), it's the same (logically).

There's a pretty big chance, that the compiler will optimize this.


In Addition - actually, this is supposed to be like this for any types at all. But it's just supposed to be. As anyone can overload operator++ - the postfix and prefix, they can have side effects and different behavior.

Well, this is a horrible thing to do, but still possible.

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
  • A horrible thing indeed. Something like abusing the shift operator to put data into a stream, right? ;-) (SCNR) – Christopher Creutzig Aug 03 '11 at 14:24
  • Well, it's a good point -- after all, you could eventually be dealing with a custom iterator which is very expensive to copy for whatever reason and cannot be optimized out, so just habitually writing what you mean (`++it`) rather than what you may have gotten used to (`c++`) is just good practice. – Kerrek SB Aug 03 '11 at 14:27
  • @Kerrek SB - exactly :) I always prefer `++bla_bla`, when it's ok to be used. – Kiril Kirov Aug 03 '11 at 14:39
1

It won't cause any problems, but using ++it is more correct. With small types it doesn't really matter to use ++i or i++, but for "big" classes:

operator++(type x,int){
    type tmp=x; //need copy
    ++x;
    return tmp;
}

The compiler may optimize out some of them, but it's hard to be sure.

Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
RiaD
  • 46,822
  • 11
  • 79
  • 123
1

As other answers have said, prefer ++it unless it won't work in context. For iterating over containers of small types it really makes little difference (or no difference if the compiler optimizes it away), but for containers of large types it can make a difference due to saving the cost of making a copy.

True, you might know in your specific context that the type is small enough so you don't worry about it. But later, someone else on your team might change the contents of the container to where it would matter. Plus, I think it is better to get yourself into a good habit, and only post-increment when you know you must.

Matt Ryan
  • 261
  • 2
  • 10