0

I have a vector that contains Enemy objects called enemiesOnField. When calling a function takeYourTurn that potentially changes the coordinates of individual enemies I noticed that even though the change occurs within the function, it doesn't persist in the enemiesOnField vector. This leads me to believe that when calling this function by iterator it is somehow called on a copy, not the original object. When calling by reference returned by the [] operator everything works normally.

The code that doesn't work as expected is commented out:

void World::letNPCsAct()
{

    /* this doesn't work
    for (auto it : enemiesOnField)      
        it.takeYourTurn();*/

    // this works
    for (int i = 0; i < enemiesOnField.size(); ++i)
        enemiesOnField[i].takeYourTurn();

}

Why is this like this??

Stevan
  • 63
  • 6
  • 1
    Your range based loop modifies *copies* of the original objects. You need to loop over references to modify the original vector. – Yksisarvinen Jan 24 '20 at 15:24
  • So something like: for (const auto& it : enemiesOnField) it.takeYourTurn(); Would work? – Stevan Jan 24 '20 at 15:28

3 Answers3

2

Normal for loop works because you are directly changing the content. Range based for loop creates copies by default. So your content won't be modified. If you want to modify, you need to use the reference as below.

for (auto& it: enemiesOnField) {    
    it.takeYourTurn();
}
kadina
  • 5,042
  • 4
  • 42
  • 83
1

Try this:

for (auto& it: enemiesOnField) {    
    it.takeYourTurn();
}

You need to iterate through references.

Toma
  • 2,764
  • 4
  • 25
  • 44
1

The range-for loop gives you the objects contained in the range, not iterators to them.

for (auto it : enemiesOnField)      
    it.takeYourTurn();

This is not calling takeYourTurn through an iterator. It is calling it on a copy of the object contained in enemiesOnField.

If you want it to use references, you must declare it to do so:

for (auto& enemy : enemiesOnField)      
    enemy.takeYourTurn();

The range-for you used is semantically equivalent to the following:

{
    auto&& __range = enemiesOnField;
    auto __begin = __range.begin();
    auto __end = __range.end();
    for (; __begin != __end; ++__begin)
    {
        auto it = *__begin;
        it.takeYourTurn();
    }
}

(Note that the names __range, __begin, and __end are for exposition only. Those objects cannot be referenced by user code)

Note that auto it = *__begin makes a copy of the object referenced by __begin.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52