Vector Iterator Issue

Hello everyone,

I have a question regarding iterators on vectors. To begin, I have the code below:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
double Convertor::ConvertStringTenorIntoYears(string Tenor)
{
    string Period;
    unsigned long nbOfPeriods;
    double Result;
    unsigned long len=(unsigned long)Tenor.size();
    Period=Tenor.substr(len-1,1);
    
    string TempNbOfPeriods=Tenor.substr(0,len-1);
    
    nbOfPeriods=(unsigned long) atoi(TempNbOfPeriods.c_str());
    
    if(Period=="D")
        Result=(double) nbOfPeriods / 360.0;            
    if(Period=="W")
        Result=(double) nbOfPeriods / 52.0;
    if(Period=="M")
        Result=(double) nbOfPeriods / 12.0;         
    if(Period=="Y")
        Result=(double) nbOfPeriods ;   
    
    return Result;
}; 

  
int main ()
{
    map<string, double> RateCurve;
    
    RateCurve["1D"  ]=4.77  ;
    RateCurve["1W"  ]=4.773 ;
    RateCurve["1M"  ]=4.773 ;
    RateCurve["2M"  ]=4.753 ;
    RateCurve["3M"  ]=4.733 ;
    RateCurve["4M"  ]=4.7   ;
    RateCurve["5M"  ]=4.673 ;
    RateCurve["6M"  ]=4.645 ;
    RateCurve["7M"  ]=4.665 ;
    RateCurve["8M"  ]=4.639 ;
    RateCurve["9M"  ]=4.634 ;
    RateCurve["10M" ]=4.619 ;
    RateCurve["11M" ]=4.623 ;
    RateCurve["1Y"  ]=4.636 ;
    RateCurve["18M" ]=4.578 ;
    RateCurve["2Y"  ]=4.635 ;
    RateCurve["3Y"  ]=4.725 ;
    RateCurve["4Y"  ]=4.805 ;
    RateCurve["5Y"  ]=4.895 ;
    RateCurve["6Y"  ]=4.995 ;
    RateCurve["7Y"  ]=5.1   ;
    RateCurve["8Y"  ]=5.182 ;
    RateCurve["9Y"  ]=5.257 ;
    RateCurve["10Y" ]=5.302 ;
    RateCurve["11Y" ]=5.36  ;
    RateCurve["12Y" ]=5.415 ;
    RateCurve["15Y" ]=5.55  ;
    RateCurve["20Y" ]=5.685 ;
    RateCurve["25Y" ]=5.745 ;
    RateCurve["30Y" ]=5.745 ;

    vector<double> Row(2);
    vector<vector<double>> ResultVector(1,vector<double>(2));
    
      
    for (map<string, double>::iterator it=RateCurve.begin() ; it!=RateCurve.end() ; it++)
    {
        Row[0]=Convertor::ConvertStringTenorIntoYears(it->first);
        Row[1]=it->second;
                              
        ResultVector.push_back(Row);
    };
        
    sort(ResultVector.begin(),ResultVector.end());
    
    return 0;
}


now if I run this :

1
2
3
4
5
6
7
8
9
10

    int i=0;
       
    for (vector<vector<double>>::iterator it=ResultVector.begin(); it!=ResultVector.end(); it++)
    {
        cout << "[" << ResultVector[i][0] << "]=" << ResultVector[i][1]<< endl;
        i++;
    }
    


I get :

[0]=0
[0.00277778]=4.77
[0.0192308]=4.773
[0.0833333]=4.773
[0.166667]=4.753
[0.25]=4.733
[0.333333]=4.7
[0.416667]=4.673
[0.5]=4.645
[0.583333]=4.665
[0.666667]=4.639
[0.75]=4.634
[0.833333]=4.619
[0.916667]=4.623
[1]=4.636
[1.5]=4.578
[2]=4.635
[3]=4.725
[4]=4.805
[5]=4.895
[6]=4.995
[7]=5.1
[8]=5.182
[9]=5.257
[10]=5.302
[11]=5.36
[12]=5.415
[15]=5.55
[20]=5.685
[25]=5.745
[30]=5.745


Up to now, i get what i want. Only the strings are converted to double in an ordered way.

The thing that I don't understand, is that using iterators like this :

1
2
3
4
5
6
for (vector<vector<double>>::iterator it=ResultVector.begin();it!=ResultVector.end();it++)
    {
        vector<double>::iterator itt=(*it).begin();
        cout << *itt << "-->" << *(itt++) << endl;
    }


I get :

0-->0
4.77-->0.00277778
4.773-->0.0192308
4.773-->0.0833333
4.753-->0.166667
4.733-->0.25
4.7-->0.333333
4.673-->0.416667
4.645-->0.5
4.665-->0.583333
4.639-->0.666667
4.634-->0.75
4.619-->0.833333
4.623-->0.916667
4.636-->1
4.578-->1.5
4.635-->2
4.725-->3
4.805-->4
4.895-->5
4.995-->6
5.1-->7
5.182-->8
5.257-->9
5.302-->10
5.36-->11
5.415-->12
5.55-->15
5.685-->20
5.745-->25
5.745-->30

it seems that I have the equivalence of Rate->Maturity and not Maturity->Rate. I mean the index and the value are reversed. Could you help me understand why?

My second question is : why I get [0]=0 at the begining? i thought that i started filling the vector from 0!!!

Thank you in advance!!

Last edited on
 
cout << *itt << "-->" << *(itt++) << endl;

Note that the postfix ++ operator returns the value of the iterator before ++ was applied. You also can't be sure if the first itt on that line will use itt after, or before ++ has been applied (but for you it seems to be after). You might want to use +1 or std::next instead.

 
cout << *itt << "-->" << *(itt+1) << endl;

 
cout << *itt << "-->" << *next(itt) << endl;


If you find it easier to use a vector you could do something like this:
1
2
3
4
5
for (vector<vector<double>>::iterator it=ResultVector.begin();it!=ResultVector.end();it++)
{
	const vector<double>& vec = *it;
	cout << vec[0] << "-->" << vec[1] << endl;
}

In C++11 (and later) you can write the above loop even more compact using a range-based for loop. It's still important to understand iterators when using range-based for loops because that is what is used behind the scene. Invalidating the iterators, which could happen if you add or remove elements from the vector that you iterate over, is an equally big problem in both cases.
1
2
3
4
for (const vector<double>& vec : ResultVector)
{
	cout << vec[0] << "-->" << vec[1] << endl;
}
Last edited on
As for you second question, the reason you have zeros in the vector is because of the constructor on line 62.
cout << *itt << "-->" << *(itt++) << endl;
First of all, that is a post-increment. Post-increment returns old value, what the object had before increment.

More important issue (and this is not specific to iterators) is that compiler can evaluate operands in any order. Your environment apparently does, in pseudo:
1
2
3
4
5
X = itt;
++itt;
Z = *X;
Y = *itt;
cout << Y <<"-->" << Z << endl;

On some other environment the order is different.
cout << *itt << "-->" << *(itt++) << endl;
You could do:
1
2
3
4
5
cout << *itt << "-->" << *(itt+1) << endl;
// OR
cout << *(*it).begin() << "-->" << *((*it).begin()+1) << endl;
// OR
cout << (*it).front() << "-->" << (*it).back() << endl;



The 0-->0:
vector<vector<double>> ResultVector(1,vector<double>(2));
Create ResultVector that has one element and initialze that element with vector<double>(2) object.

vector<double>(2)
Create a vector that contains two double elements. I cannot remember whether they are zero-initialized by standard, or is it just your compiler's decision.

In other words: you add explicitly the "unexpected" entry.

But why use a vector at all? The "two doubles" nature is known at compile-time.
1
2
3
4
5
vector<std::pair<double,double>> ResultVector;
// or
vector<std::array<double,2>> ResultVector;

ResultVector.reserve( RateCurve.size() );
Hey thanks!

It works with next(itt) . Oh so you mean that next(itt) is not equivalent to itt++ !! why is that? i expect that doing itt++ in for (vector<vector<double>>::iterator itt=ResultVector.begin();itt!=ResultVector.end();itt++) helps to scroll through the vector in an ordered way.

True for my second question. thanks again!
Last edited on
std::next does not modify the iterator. It simply returns the iterator that comes after.

The ++ operator comes in two versions. The postfix (itt++) and the prefix (++itt). Both of them modify the iterator in the same way. The difference between them is that the postfix operator returns the old iterator value while the prefix operator returns the new iterator value.
Last edited on
1
2
3
4
5
auto it2 = next( it1);

// is same as
auto it2 = it1;
++it2;


Prefer the prefix / pre-increment (and pre-decrement). The post-version is canonically implemented with the pre-version:
1
2
3
4
5
6
7
8
9
10
11
12
Foo   Foo::operator++ (int) // post-increment
{
  Foo temp( *this );
  ++(*this); // call pre-increment
  return temp;
}

Foo & Foo::operator++ () // pre-increment
{
  // increment internal data
  return *this;
}

The for-loop increments the iterator without making use of the returned value, so the use of pre-increment is recommended. (The compiler might be able to optimize needless code (the temp) out, but why assume when you can be explicit?)
ok I see now. Really thanks for everyone!!

I only need one last thing. in the code below i'm trying to get the value which fallows a specified value:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
double Curve::getTenorSup(double const Tenor)
{
    double TenorSup;
    double TenorResult;
    
    for(vector<vector<double>>::iterator itRow=DoubleTenorVectorCurve.begin(); itRow!=DoubleTenorVectorCurve.end();itRow++)
    {
        vector<double>::iterator TenorIterator=(*itRow).begin();
        TenorSup=*TenorIterator;
        if (Tenor<=TenorSup)
		{
            TenorResult=TenorSup;
			return TenorResult;
		};
	};
};


i got a warning : 'not all control paths return a value'

this function may not return a double if it doesn't find a value. this causes me some trouble. how can I manage this?

thank you
The caller expects a value no matter what. You have to indicate failure somehow.

How about return std::pair<double,bool>
Topic archived. No new replies allowed.