Malcolm Crum
Malcolm Crum

Reputation: 4869

Casting an iterator to a pair of objects

I don't understand the following:

#include <iostream>
#include <vector>
using namespace std;

class Date {
public:
    Date(int y, int m) {
        year = y;
        month = m;
    }
    int year;
    int month;
};

int main() {
    vector<pair<Date, Date> > ranges;
    Date date1 = Date(2000, 1);
    Date date2 = Date(2000, 2);
    ranges.push_back(pair<Date, Date>(date1, date2));

    for (vector<pair<Date, Date> >::iterator it = ranges.begin(); it != ranges.end(); ++it) {
        (*it).first.year = 2002;
        pair<Date, Date> range = *it;
        range.first.year = 2001;
    }
    cout << ranges[0].first.year << endl;
}

When I run this, "2002" outputs, though I expected "2001".

It seems that casting an iterator does not work as I expected. I can access range fine, and read its variables, but I cannot change them - or at least, the changes don't stick.

I've fixed my problem by using (*it) instead of casting, but I'd like to know why my casting does not work.

Upvotes: 0

Views: 1180

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 310950

In the loop

for (vector<pair<Date, Date> >::iterator it = ranges.begin(); it != ranges.end(); ++it) {
    (*it).first.year = 2002;
    pair<Date, Date> range = *it;
    range.first.year = 2001;
}

range is a local variable of the loop. In each iteration of the loop (there is only one iteration because the vector contains only one element) this variable is initialized by a copy of the value of the element of the vector. So any changes of this local variable do not influence on the elements of the vector. The vector itself was not changed.

Instead of these two lines

    pair<Date, Date> range = *it;
    range.first.year = 2001;

you could write simply

( *it ).first.year = 2001;

In this case you would directly change the element of the vector.

Or the other way to change the value of an element of the vector is to use a reference to the element instead of creating a separate object. For example

for (vector<pair<Date, Date> >::iterator it = ranges.begin(); it != ranges.end(); ++it) {
    (*it).first.year = 2002;
    pair<Date, Date> &range = *it;
    range.first.year = 2001;
}

In this case as the reference is used the original element of the vector will be changed.

Upvotes: 1

imreal
imreal

Reputation: 10358

I recommend using range-based for loops instead, like this:

for (auto& range : ranges)
{
    ...
    range.first.year = 2001;
    ...
}

You can use a reference, like in the example above, and modify the collection directly.

Upvotes: 1

Related Questions