
Interesting logic of random access iterators in STL containers
In programming courses, I got the task of writing an analogue of std :: vector in C ++ with preserving the functional and interface, in order to make it at least twice as fast, a million times more readable. During execution, I came across the fact that Random access iterators have some very strange interesting features that I wanted to change. Who cares - welcome to cat.
On Habré there is already a good article on iterators here
From myself I want to add only the definition from the article on iterators on Wikipedia.
An iterator is an object that abstracts access to the elements of a collection behind a single interface.
So, create two integer vectors:
Fill both numbers from 0 to 14:
Create iterators for each vector:
The first thing that caught my eye was the presence of an overloaded operator "-" and the absence of an overloaded operator "+" for two iterators (adding an iterator with an int is provided). Create an additional iterator for the first vector and do both actions:
In the first case, we get output 3, in the second - a compilation error.
Secondly, I was interested in the issue of equality of iterators. Based on the definition, the iterator should provide access to the elements of the collection. That is, if two iterators belong to different collections, the cap suggests that you cannot compare them at all. However:
At the output we have “Not equal”, which, with the strangeness of the very possibility of such a comparison, is very logical.
After I realized that it is possible to compare iterators of different objects, I decided to try to subtract one from the other:
At the exit we get 34. I immediately remembered Pelevin and his "Numbers".
The fact that at the output we get an unpredictable int is related to how the vectors are located in memory relative to each other. Having tried to fill both vectors with a different number of numbers, I got a completely different result.
Well and the most interesting:
At the exit, you guessed it, Equal. This leads to the following conclusion, which is unfavorable from my point of view, that:
will allow us to iterate the first vector, not the second.
When creating Random access iterator, the developers did not limit the use of the iterator to the scope of the container for which it was created. I can understand their logic, although I personally do not like it. Close comparison and subtraction of iterators pointing to different vectors would not be very difficult. And although, perhaps, such situations are rare, do not forget about these features.
Briefly about iterators
On Habré there is already a good article on iterators here
From myself I want to add only the definition from the article on iterators on Wikipedia.
An iterator is an object that abstracts access to the elements of a collection behind a single interface.
Create an iterator
So, create two integer vectors:
vector vector1;
vector vector2;
Fill both numbers from 0 to 14:
for ( int i = 0; i < 15; i++ ) {
vector1.push_back(i);
vector2.push_back(i);
}
Create iterators for each vector:
vector::iterator it1 = vector1.begin();
vector::iterator it2 = vector2.begin();
Actually interesting features
The first thing that caught my eye was the presence of an overloaded operator "-" and the absence of an overloaded operator "+" for two iterators (adding an iterator with an int is provided). Create an additional iterator for the first vector and do both actions:
vector::iterator temp = vector1.begin() + 3;
cout << temp - it1 << endl;
cout << temp + it1 << endl;
In the first case, we get output 3, in the second - a compilation error.
Secondly, I was interested in the issue of equality of iterators. Based on the definition, the iterator should provide access to the elements of the collection. That is, if two iterators belong to different collections, the cap suggests that you cannot compare them at all. However:
if ( it1 == it2 ) {
cout << "Equal" << endl;
} else {
cout << "Not equal" << endl;
}
At the output we have “Not equal”, which, with the strangeness of the very possibility of such a comparison, is very logical.
After I realized that it is possible to compare iterators of different objects, I decided to try to subtract one from the other:
cout << it1 - it2 << endl;
At the exit we get 34. I immediately remembered Pelevin and his "Numbers".
Brief Summary
The hero of Pelevin's new novel, The Numbers, is Stepan’s businessman. As a child, Styopa realized that he was not like everyone else. Styopa felt an inexplicable latent craving for the number 7, but did not understand how to please this great number, which is worshiped by so many talented people. As a result, he realized that 7 is nothing more than 3 + 4 (which we will see later), so he began to worship the number 34, subjecting him to his whole life.
Taken from pelevin.nov.ru/stati/o-lleo2/1.html
Taken from pelevin.nov.ru/stati/o-lleo2/1.html
The fact that at the output we get an unpredictable int is related to how the vectors are located in memory relative to each other. Having tried to fill both vectors with a different number of numbers, I got a completely different result.
Well and the most interesting:
it2 += 34;
if ( it1 == it2 ) {
cout << "Equal" << endl;
} else {
cout << "Not equal" << endl;
}
At the exit, you guessed it, Equal. This leads to the following conclusion, which is unfavorable from my point of view, that:
it2 = vector2.begin() + 34;
will allow us to iterate the first vector, not the second.
conclusions
When creating Random access iterator, the developers did not limit the use of the iterator to the scope of the container for which it was created. I can understand their logic, although I personally do not like it. Close comparison and subtraction of iterators pointing to different vectors would not be very difficult. And although, perhaps, such situations are rare, do not forget about these features.