Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Qt foreach create a copy of the container?

The documentation simply states that it does, but doesn't explain why:

Qt automatically takes a copy of the container when it enters a foreach loop. If you modify the container as you are iterating, that won't affect the loop. (If you do not modify the container, the copy still takes place, but thanks to implicit sharing copying a container is very fast.) Since foreach creates a copy of the container, using a non-const reference for the variable does not allow you to modify the original container. It only affects the copy, which is probably not what you want.

To me it looks like a self-imposed handicap, making Qt's foreach less useful than it could have been - now you can't use it to modify elements.

I've heard that boost's foreach and the new C++11 for (auto iter : array) do not perform a copy (although I'm not familiar with any of them).

So what is the rationale behind that copying?

like image 638
sashoalm Avatar asked May 12 '14 15:05

sashoalm


People also ask

Which is faster for or foreach in C++?

Foreach performance is approximately 6 times slower than FOR / FOREACH performance. The FOR loop without length caching works 3 times slower on lists, comparing to arrays. The FOR loop with length caching works 2 times slower on lists, comparing to arrays.

How do I iterate through a QList?

QList<T>::iterator allows you to iterate over a QList<T> (or QQueue<T>) and to modify the list item associated with the iterator. If you want to iterate over a const QList, use QList::const_iterator instead.

Does C++ have foreach?

The working of foreach loops is to do something for every element rather than doing something n times. There is no foreach loop in C, but both C++ and Java have support for foreach type of loop. In C++, it was introduced in C++ 11 and Java in JDK 1.5.


1 Answers

The Qt developers have decided about the use case that it should prevent from surprises when you modify the container in the loop (like in a signal handler, a. k. a. slot, etc) without modifying the original container.

It could be tricky with the signal-slot mechanism to track down whether something is modified. It would be basically up to the slot if you emit the signal with that container member. To be sure, you would always need to do the external copy otherwise.

Another advantage is that you could pass a method call to the second parameter without continuous re-evaluation because the copy will be created the first time. This is actually quite a neat feature if you ask me because often, you wish to iterate over the associate array keys or values like myHash.keys() or myHash.values().

You could argue that boost also has signal-slot mechanism. Yes, it is just a different way of doing it in my opinion. They do not have to be doing the same always. :-)

Different people have different taste about API, styling, and so on. After all, you have all the tools in your hand to achieve whatever use case you plan to deal with.

You could also argue that it may not be what you want and you would do an explicit copy instead. That is fair enough, you can go as far as that with Boost or the standard foreach in C++.

There are no performance concerns in here with the copy since for normal iteration without modification the copy-on-write (a. k. a. implicit sharing) is good enough. It has some performance overhead, but it is negligible.

The right Qt semantic for such a use case would be to use the iterator design pattern. Qt has iterator classes all over the place following the "Java style", for instance.

like image 73
lpapp Avatar answered Oct 08 '22 03:10

lpapp