tags:

views:

173

answers:

2

Hi! I have a few foreach related questions below I hope that somebody could answer. I know that most people do not care about the possibly insignificant differences, but I want to understand them for completeness.

1) Could somebody explain how the foreach keyword in Qt actually works behind the scenes. I would like to know if foreach creates a new item object pointer and reevaluates the collidingItems (potentially expensive) on each iteration in the below example

foreach (QGraphicsItem *item, someItem->collidingItems(Qt::IntersectsItemShape) {
    // do something with item;
}

and should it hence be typed like this

QGraphicsItem *item;
QList<QGraphicsItem *> itemList = someItem->collidingItems(Qt::IntersectsItemShape);
foreach (item, itemList) {
    // do something with item;
 }

I assume a no, since according to documentation it takes a copy of the list before entering the loop. However, if I recall correctly, at least a for statement evaluates the check on every iteration, so I just want to be sure.

2) Second question. Since foreach makes a copy of the list, is it ok to change the original inside the foreach as in

QList<QGraphicsItem *> itemList = someItem->collidingItems(Qt::IntersectsItemShape);
foreach (QGraphicsItem *item, itemList) {
    if (item->type() != QGraphicsItem::UserType)
        itemList.removeOne(item);
}
// continue using itemList

3) A final question. Is there any difference performance vise to precreate and reuse the pointer (shown below) or defining a new pointer inside foreach loop every time (assume a large list)?

MyGraphicsItem *myItem;   // a complex subclass of QGraphicsItem
foreach (QGraphicsItem *item, someItem->collidingItems(Qt::IntersectsItemShape)) {
    myItem = qgraphicsitem_cast<MyGraphicsItem *>(myItem);
    // do something with myItem;
}

Thank you!

A: 
  1. It really makes a copy of the list you pass as the second argument of foreach. In your case, the list returned by collidingItems will be copied into a variable used inside foreach.
  2. Yes, this is ok (see below).
  3. I don't think there will be a performance difference because a pointer is a primitive type. If it where a class type, its constructor would have to be called every iteration if you declared it inside the loop.

From the docs:

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 don't modify the container, the copy still takes place, but thanks to implicit sharing copying a container is very fast.)

Job
A: 

Job has already answered this pretty thoroughly. I'd just like to add that the performance difference of using foreach instead of a normal for loop is probably so insignificant that you'd never be able to measure it. In other words, this isn't a performance problem that you should be concerned with.

Use a profiler to measure the bottlenecks in your code and focus on optimizing the parts that are actually slow.

Cutterpillow