Reputation: 87
I'm having issues implementing an iterator class in regards to .end(). The problem I'm running into is when I try to use a for loop with my iterator class; it's currently stopping just before the last element in a 2D vector. However, I want it to go one element past the last element without causing a compiler error, and to include the last character in the print statement.
main.cpp
// file contents
// aaa
// bbb
// cce
// factory method (adds file contents to 2D <char> vector)
Base *a = Base::create("file");
cout << *a; // overloaded '<<'
Prints
a a a b b b c c e
Now, when I use a for loop with my iterator class, it doesn't include the last character.
for(auto it = a->begin(); it != a->end(); it++)
cout << *it << ' ';
Prints
a a a b b b c c
The .end prints the following
Base::iterator it = aa->end();
cout << *it << '\n';
// prints e
When I try a while loop, it includes the last character.
// Note: my iterator class is a nested class inside Base class.
const Base::iterator et = a->begin();
int i = 0;
while(i < 13) {
cout << *et << ' ';
et++;
}
Prints
a a a b b b c c e e e e e
I understand that a->end() is supposed to point just past the last character, but I don't understand how to implement that. When I increment past the last value in my operator++(int), it displays a segmentation fault. Currently, my overloaded increment method stops at the last character and doesn't go past it. With that said, how do I implement my ++(int) method to include the last element when printing from a for loop? Am I supposed to add a null element to the vector or something like that?
Inside Base.cpp
// This function is whats causing the issue. I know it looks ugly.
Base::iterator Base::iterator::operator++(int) {
// base is a Base *, x and y are coordinates for 2D vector
Base::iterator temp(base, x, y); // save value
// if iterator has not reached end
if( !((x == base->vec.size()-1) && (y == base->vec[0].size()-1)) )
{
// if y < row size
if(y < base->vec[0].size()-1)
y++;
// if y has reached end of row, increment x and start y on a new row
else if(x < base->vec.size() && y == base->vec[0].size()-1) {
y=0;
x++;
}
}
return temp;
}
Base::iterator Base::begin() {
return Base::iterator(this, 0, 0);
}
Base::iterator Base::end() {
return Base::iterator(this, vec.size()-1, vec[0].size()-1);
}
Rest of Base.cpp
#include "Base.h"
using namespace std;
// Factory method (instantiates 2D vector with file contents)
Base *Base::create(string filename) {/*removed irrelevant code */}
Base::~Base(){}
// prints 2D vector
ostream &operator<<(ostream &os, const Base &val){/*removed irrelevant code*/}
Base::iterator::iterator(Base *b, int m, int n): base(b), x(m), y(n) {}
Base::iterator::~iterator(){}
// returns a character inside 2D vector
char &Base::iterator::operator*() const {
return base->vec[x][y];
}
bool Base::iterator::operator==(const Base::iterator& rhs) const {
return base->vec[x][y] == *rhs;
}
bool Base::iterator::operator!=(const Base::iterator& rhs) const {
return base->vec[x][y] != *rhs;
}
// Bunch of other functions
Any help would be appreciated.
Upvotes: 2
Views: 88
Reputation: 22033
Base::iterator(this, vec.size()-1, vec[0].size()-1);
this will return a valid last element. So you need to change it to Base::iterator(this, vec.size(), 0);
, and also update the conditions to switch to a new row in your loop.
Something like:
// if iterator has not reached end
if(x < base->vec.size())
{
++y;
// if y has reached end of row, increment x and start y on a new row
if(y >= base->vec[0].size() {
y=0;
++x;
}
}
Also the iterators are wrong:
bool Base::iterator::operator==(const Base::iterator& rhs) const {
return base == rhs.base && x == rhs.x && y == ris.y;
}
bool Base::iterator::operator!=(const Base::iterator& rhs) const {
return !(base == rhs.base && x == rhs.x && y == ris.y);
}
Upvotes: 1