PDA

View Full Version : strange behavior of QMapIterator



alainstgt
7th February 2015, 01:55
Hello community!

I have following situation:


typedef QMapIterator<double, QCPFinancialData> QCPFinancialDataMapIterator;

class QCP_LIB_DECL QCPFinancialData
{
public:
QCPFinancialData();
QCPFinancialData(double key, double open, double high, double low, double close);
double key, open, high, low, close;
friend QDebug operator<<(QDebug dbg, QCPFinancialData& data); // AW
};

Here the code snippet:


QCPFinancialDataMap map;
QCPFinancialDataMapIterator it( map );
// initialize map ...
// map after initialization:
map = QCPFinancialDataMap(QMap(0,QCPFinancialData(0,10,1 5,8,12) ) QMap(900,QCPFinancialData(900,11,16,7,13) ) QMap(1800,QCPFinancialData(1800,12,17,6,14) ) QMap(2700,QCPFinancialData(2700,13,18,5,15) ) )
. . .
// I make 3 calls to it.next(), all behaving as expected.
Then I have to go one step backwards, so I call it.previous(), but without any effect! I have to make a second call to it.previous() to get the desired result! Same behavior moving the iterator forward to reach the original position! - see code snippet and printout -


qDebug() << "1: it.value().close =" << it.value().close; // OK, is 14
it.previous(); // no effect!
qDebug() << "2: it.value().close =" << it.value().close; // should be 13!
it.previous(); // works as expected. Why is a double call of previous() necessary?
qDebug() << "3: it.value().close =" << it.value().close; // OK, is 13
currentBinData.close = it.value().close;
it.next(); // no effect!
qDebug() << "4: it.value().close =" << it.value().close; // should be 14!
it.next(); // works as expected. Why is a double call of next() necessary?
qDebug() << "5: it.value().close =" << it.value().close; // OK, is 14

print out:
1: it.value().close = 14
2: it.value().close = 14
3: it.value().close = 13
4: it.value().close = 13
5: it.value().close = 14

The code is doing what I want, but it is not clean.
Any idea?

Thank you for your time.
Alain

jefftee
7th February 2015, 02:25
Hi, each next() or previous() moves the iterator after or before an item accordingly. The value() then returns the item that was skipped over by the next() or previous() methods, so the iterator is always moved past an item (for next) or moved before an item (for previous).

The behavior of next() and previous() is undefined if you are past the end or before the beginning respectively. You don't really show where your iterator is sitting before you posted your example. My guess is that your iterator was pointing just past 14 (after a next call) when you ran the code shown in your post.

Seems to me you should be moving your iterator with previous() and next() before you print the value() because the value() points to the item skipped over.

Here's is what you posted for your example:





qDebug() << "1: it.value().close =" << it.value().close; // OK, is 14
it.previous(); // no effect!
qDebug() << "2: it.value().close =" << it.value().close; // should be 13!
it.previous(); // works as expected. Why is a double call of previous() necessary?
qDebug() << "3: it.value().close =" << it.value().close; // OK, is 13
currentBinData.close = it.value().close;
it.next(); // no effect!
qDebug() << "4: it.value().close =" << it.value().close; // should be 14!
it.next(); // works as expected. Why is a double call of next() necessary?
qDebug() << "5: it.value().close =" << it.value().close; // OK, is 14



Here's what I believe happens for each of your steps. The "I" below shows where the iterator is pointing for each step (again, I am assuming your have iterated past 14 using next() but not shown in your example):



12 13 14 I 15 // prints 14 because I am guessing you had iterated past 14 using next() prior to the example you posted
12 13 I 14 15 // after your call to previous()
12 13 I 14 15 // prints 14 because it was the most recent item skipped over (again)
12 I 13 14 15 // after your call to previous()
12 I 13 14 15 // prints 13 because it was most recent item skipped over
12 I 13 14 15 // this line of your code has no effect on the iterator, so no changes here
12 13 I 14 15 // after your call to next()
12 13 I 14 15 // prints 13 because it was the most recent item skipped over (again)
12 13 14 I 15 // after your call to next()
12 13 14 I 15 // prints 14 because it was the most recent item skipped over


The key is that the iterator never points exactly at an item, it points just before an item or just after an item, so when you switch directions, you traverse the same item twice.

Hope that helps.

anda_skoa
7th February 2015, 09:23
If you want an iterator that points to a respective entry instead of between entries, you can use STL-style ones.



QCPFinancialDataMap::const_iterator it = map.constBegin();
// it points to first entry

++it;
// it points to second entry

--it;
// it points to first entry


Cheers,
_

alainstgt
7th February 2015, 11:53
thank you to both!

I was not aware that the the value() points to the item skipped over!
You are right guessing that I had iterated past 14 , jthomps. Your description matches exactly my situation.

Using a STL-like iterator is in that case more elegant.
I used the Java-style iterator because it is defined as typedef in the library (qcustomplot) I am using.

Alain