Home > OS >  Vector Iterators Incompatible: proper way to iterate over two vectors?
Vector Iterators Incompatible: proper way to iterate over two vectors?

Time:11-07

One of my teachers has tasked us with creating a class that can iterate over two different vectors to make them appear as though they are contiguous from the pov of the caller. One of the requirements is that the vectors mustn't be copied. From what I understand, iterators from two different vectors cannot be compared so I fail to see what the proper way to write this class would be. Here's the teacher's version with a few fixes from me:

class concat {
    std::vector<std::string>& vec1;
    std::vector<std::string>& vec2;

public:
    concat(std::vector<std::string>& v1, std::vector<std::string>& v2) : vec1(v1), vec2(v2) {}

    class iterator {
        std::vector<std::string>::iterator it;
        concat* context;

    public:
        iterator(std::vector<std::string>::iterator& it, concat* context) : it(it), context(context) {}

        std::string& operator*() {
            return *it;
        }
        iterator& operator  () {
            it  ;
            if (it == context->vec1.end())
                it = context->vec2.begin();

            return *this;
        }
        bool operator!=(const iterator& other) const {
            return (context != other.context) || (it != other.it);
        }
    };

    iterator begin() { return iterator(vec1.size() ? vec1.begin() : vec2.begin(), this); }
    iterator end()   { return iterator(vec2.end(), this); }
};

And the corresponding main:

vector<string> v1;
v1.push_back("abc"); v1.push_back("def");

vector<string> v2;
v2.push_back("ghi"); v2.push_back("jkl");

concat conc = concat(v1, v2);
for (const string& s : conc)
   cout << s << ":";

This fails on debug with a "Debug Assertion Failed" message: Vector Iterators Incompatible on line return (context != other.context) || (it != other.it); using Visual Studio 2019.

CodePudding user response:

The way to do this is to hold internally two iterators. One to vec1, the other to vec2. First use the first one, then after the first one reaches the end of vec2 switch to the other one.

Some snippets to see what I mean:

itnerator& operator  ()
{
   if (it1 != vec1.end())
        it1;
   else
        it2;
   return *this;
}
std::string& operator*()
{
     if (it1 != vec1.end())
         return *it1;
     else
         return *it2;
}
  • Related