++ is ++ when iterating over a map?

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

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

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

+7
source share
6 answers

Putting it into the test, I created 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 found that versions 2 and 3 produce the same build, and version 1 differs only in one instruction cmpl %eax, %esi vs cmpl %esi, %eax .

So, take your choice and use what suits your style. Incrementing the ++it prefix is ​​probably best because it most closely reflects your requirements, but don't get stuck in it.

+10
source

it++ returns a copy of the previous iterator. Since this iterator is not used, it is useless. ++it returns a link to an incremental iterator, avoiding copying.

See Question 13.15 for more details.

+20
source

Theres a slight performance advantage when using pre-increment statements and post-increment statements. When setting up loops that use iterators, you should use pre-increments:

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

The reason becomes clear when you think about how both statements are usually executed. The preliminary increment is quite simple. However, in order for the post-increment to work, you first need to make a copy of the object, make the actual increment of 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 implementation after the increment includes two additional copy operations. This can be quite expensive if the item in question is bulky. Having said that, some compilers may be smart enough to get away with a single copy operation through optimization. The fact is that a post-increment will usually include more work than a pre-increment, and therefore it is wise to use it to place your "++" in front of your iterators, and not after.

(1) Credit to a linked website.

+7
source

In a logical point of view - this is the same and here it does not matter.

Why is the prefix used because it is faster - it changes the iterator and returns its value, while the postfix creates a temp object, increments the current iterator, and then returns the temp object (a copy of the same iterator before increasing). Since no one is watching this temporary object here (return value), it is the same (logically).

There is a very big chance that the compiler will optimize this.


In addition - in fact, it should be like for any type in general. But it just has to be. Since anyone can overload operator++ - postfix and prefix, they can have side effects and other behavior.

Well, it's terrible, but still possible.

+6
source

This will not cause any problems, but using ++it more correct. With small types it does not matter to use ++i or i++ , but for "large" classes:

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

The compiler can optimize some of them, but it is difficult to do.

+1
source

As the other answers said, prefer ++ if this doesn't work in context. For iteration over containers of small types, this is really not much different (or there is no difference if the compiler optimizes it), but for containers of large types this can make a difference due to the cost of creating a copy.

True, you may know in your specific context that the type is small enough so that you do not worry about it. But later, someone from your team can change the contents of the container to where it matters. In addition, I think it’s better to get used to a good habit and only post-increment when you know what you should.

+1
source

All Articles