Reputation: 49
I am designing my own generic tree container and am using the STL as a reference. However, when implementing my iterator class I noticed something about the STL's use of iterators.
As an example, the std::vector
class relies on iterators as arguments for many of its methods. (ie. erase(const_iterator position)
)
This got me wondering: what happens if, given two vectors of the same template type, and the first vectors iterator is supplied to the second vector in a method call, what happens? To help answer this question I have put together a simple program to illustrate my thoughts.
// Example program
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
void printVec(const std::string &label, const std::vector<int> &vec){
for (unsigned int i=0; i<vec.size(); i++){
std::cout << ::std::setw(3) << vec[i] << ", ";
}
std::cout << std::endl;
}
int main()
{
std::vector<int> test={0,1,2,3,4,5,6,7,8,9};
std::vector<int> test2{10,11,12,13,14,15,16,17,18,19};
std::vector<int>::iterator iter=test.begin();
std::vector<int>::iterator iter2=test2.begin();
printVec("One",test);
printVec("Two",test2);
for (int i=0; i<5; i++, iter++, iter2++);
std::cout << "One Pos: " << *iter << std::endl;
std::cout << "Two Pos: " << *iter2 << std::endl;
test.erase(iter2); //Switching the iterators and there respective vectors
test2.erase(iter); //Switching the iterators and there respective vectors
printVec("One",test);
printVec("Two",test2);
}
Running this program results in a seg. fault, which seems to indicate that this is undefined behavior. I hesitate to call this a flaw in the STL vector interface, but it sure seems that way.
So my question is this: is there any way to avoid this when designing my own container?
Upvotes: 0
Views: 23
Reputation: 32717
The iterator passed to a member function of a container must refer to an element within that container (or, in some cases, the past-the-end element returned by end()
). If the iterator does not refer to the container you have Undefined Behavior.
There is no simple way to avoid that. About the closest you can come is to validate the iterators, which means you'd have to keep track of the container each iterator belongs to. This gets a bit complicated with some operations like swap
or insert
that don't invalidate existing iterators but leave them referring to the new container.
Some compilers, like Visual C++ when compiling in debug mode, can detect these sorts of problems at runtime and issue an appropriate notification.
Upvotes: 1