i have to implement a forward iterator on a stack based on arrays. I can't use std::vectors or anything, i just need that. My development of this program stopped when i begun with forward iterator, and in particular with the operators.
I have a method that takes a generic sequence, and from that, given an offset, creates a stack:
template <typename IterT>
stack(IterT begin, IterT end) : _stack(0), _size(0), _capacity(0) {
try {
for(; begin!=end; ++begin) {
push(static_cast<T>(*begin));
}
}
catch(...) {
clear(); //my method to destroy the stack
throw;
}
}
In my main i do the following:
int a[5] = {1, 2, 3, 4, 5};
stack<int> sint(a, a+5);
cout << sint << endl;
But when the code runs the stack is created but not printed. Can somebody help me? And also give me other helps(on code indentation, improvements, etc...) Thank you, I will post the iterator code forward.
class const_iterator {
const T* data;
unsigned int index;
public:
typedef std::forward_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
const_iterator() : data(0){}
const_iterator(const T* arr) : data(arr) {}
const_iterator(const const_iterator &other)
: data(other.data){ }
const_iterator& operator=(const const_iterator &other) {
data = other.data;
return *this;
}
~const_iterator() {
data = 0;
}
reference operator*() const {
return *data;
}
pointer operator->() const {
return &(data);
}
const_iterator operator++(int) {
const_iterator tmp(*this);
++*this;
return tmp;
}
const_iterator& operator++() {
++data;
return *this;
}
bool operator==(const const_iterator &other) const {
return data[index] == other.data[index];
}
bool operator!=(const const_iterator &other) const {
return data[index] != other.data[index] ;
}
private:
friend class stack;
const_iterator(unsigned int ind) :
index(ind){}
}; // class const_iterator
const_iterator begin() const {
cout << "begin" << _stack[_size-1] << endl;
return const_iterator(_stack[_size-1]);
}
const_iterator end() const {
cout << "end" << _stack[0] << endl;
return const_iterator(_stack[0]);
}
Last but not least i redefined the << operator to fit the iterator:
template <typename T>
std::ostream &operator<<(std::ostream &os, const stack<T> &st) {
typename stack<T>::const_iterator i, ie;
for(i = st.begin(), ie = st.end(); i!=ie; ++i){
os << *i << std::endl;
}
return os;
}
The code for the stack is the following (I omitted something for readability).
stack()
: _capacity(0), _size(0), _stack(0){}
void push (const T &value){
if (_size == _capacity){ //raddoppio la dimensione
if(_capacity == 0)
++_capacity;
_capacity *= 2;
T* tmp = new T[_capacity];
copy_n(_stack, _size, tmp);
swap(_stack, tmp);
delete[] tmp;
}
_stack[_size] = value;
++_size;
}
void pop(){
T _tmp;
if(!is_empty()){
_tmp = _stack[_size-1];
--_size;
}
}
If you want to create an iterator that looks like a pointer, you don't need index, because data plays its role. Comparison operator should compare datas, not values:
bool operator==(const const_iterator &other) const {
return data == other.data;
}
If you want to create a reverse iterator, it is slightly more complex. First, operator++ should decrement data. Second, dereference operator should return not *data, but *(data - 1). Third, data in the begin() iterator should point to stack[size], and data in the end() iterator should point to stack[0]. You don't need a destructor in any case.
I followed the previous advices and here's the edited result, still i can't figure out how to properly use the constructor in the private section
class const_iterator {
const T *data;
public:
/* ITERATOR TRAITS HERE */
const_iterator() : data(0){}
const_iterator(const T* arr) : data(arr) {}
const_iterator(const const_iterator &other)
: data(other.data){ }
const_iterator& operator=(const const_iterator &other) {
data = other.data;
return *this;
}
~const_iterator() {
data = 0;
}
reference operator*() const {
return *data;
}
pointer operator->() const {
return &(data);
}
const_iterator operator++(int) {
const_iterator tmp(*this);
++*this;
return tmp;
}
const_iterator& operator++() {
++data;
return *this;
}
bool operator==(const const_iterator &other) const {
return data == other.data;
}
bool operator!=(const const_iterator &other) const {
return data != other.data;
}
private:
friend class stack;
const_iterator(const T *d) {
data = d;
}
}; // classe const_iterator
const_iterator begin() const {
return const_iterator(_stack[_size-1]);
}
const_iterator end() const {
return const_iterator(_stack[0]);
}
Related
I am trying to handle std::list of pointer type, like this:
std::list<int*> pNums;
Originally, iterating this container with range-based for loop will look like this :
for(int* pNum : pNums)
{
std::cout << (*pNum) << std::endl;
}
However, I want to iterate this container with a value, not a pointer, like below:
for(int num : Range(pNums))
{
std::cout << num << std::endl;
}
|
Here, Range is a custom wrapping-class of std::list<int*>, something should be defined in this manner, I guess:
class Range
{
Range(std::list<int*>& _list) : list(_list) {}
std::list<int*>& list;
// Basically inherit the original iterator
class custom_const_iterator : std::list<int*>::const_iterator
{
// Define an overloaded dereference operator
const int& operator*() const
{
...
}
...
};
public:
custom_const_iterator begin() { return ...; }
custom_const_iterator end() { return ...; }
};
So, my question is, what should I write down for class Range?
I would take the following approach (explanation in the comments):
class Range
{
private:
// Store iterators to the begin and the end of the range,
// rather than a reference to the whole list
std::list<int*>::const_iterator first;
std::list<int*>::const_iterator last;
class iterator
{
private:
std::list<int*>::const_iterator it;
public:
explicit iterator(std::list<int*>::const_iterator i) : it(i) {}
// you should define all the other operators
// that a std::list iterator has!
iterator& operator++()
{
++it;
return *this;
}
iterator operator++(int)
{
it++;
return *this;
}
// just dereference to get the value
const int& operator*() const { return **it; }
// these two are quite important for basic functionality
bool operator==(const iterator& rhs) const { return it == rhs.it; }
bool operator!=(const iterator& rhs) const { return it != rhs.it; }
};
public:
Range(std::list<int*>& _list)
: first(_list.begin()), last(_list.end())
{}
public:
iterator begin() { return iterator(first); }
iterator end() { return iterator(last); }
};
I have an iterator class for a queue (implemented as a circular array). I attach the code below. The problem is with the ++ operator. Once it reaches the end of the array, it circles back to its beginning, so the iterator points to the 1st element. It works fine but I have no way of implementing then end() iterator using this method. The functions that return the begin() and end() iterators inside the queue class can be seen at the bottom. The end() iterator should point to the rear of the queue, but when the array is full and rear equals the size of the array is does not work, the ++ operator will circle back instead of allowing it to the return the true end(), which is the element pointed by the rear. Any suggestions regarding this issue?
class IteratorForwQueue : std::iterator<std::forward_iterator_tag, P*> {
public:
typedef IteratorForwQueue iter;
IteratorForwQueue(P* e, Queue* q) : elem(e), _queue(q) {}
IteratorForwQueue(const IteratorForwQueue& it, Queue* q) :
elem(it.elem), _queue(q) {}
iter& operator++() {
if(elem >= (_queue->_elems + (_queue->_size - 1)) &&
_queue->_rear != _queue->_size)
elem = &(_queue->_elems[0]); // circle back passed the array
else
++elem;
return *this;
}
P& operator*() { return *elem;}
P* operator->() { return elem; }
bool operator==(const iter& it) { return elem == it.elem; }
bool operator==(const P& e) { return e == *elem; }
bool operator!=(const iter& it) { return elem != it.elem; }
bool operator!=(const P& e) { return e != *elem; }
private:
P* elem;
Queue<P>* _queue;
}; // end of iterator class
// ....
IteratorForwQueue begin() { return IteratorForwQueue(_elems + _front, this); }
IteratorForwQueue end() { return IteratorForwQueue(_elems + _rear, this); }
How about this, based on the idea that end does not have to be a "past-the-end" iterator, it can be anything:
class IteratorForwQueue : std::iterator<std::forward_iterator_tag, P*> {
public:
typedef IteratorForwQueue iter;
IteratorForwQueue(P* e, size_t sz, size_t rear) : elem(e), _base(e), _sz(sz), _rear(rear) {}
IteratorForwQueue(const IteratorForwQueue& it, size_t sz) :
elem(it.elem), _base(it.elem), _sz(sz) {}
iter& operator++() {
if(elem - _base == _rear) {
elem = nullptr;
_base = 0;
_sz = 0;
_rear = 0;
return *this;
}
if(elem >= _base + (_sz - 1))
elem = _base; // circle back passed the array
else
++elem;
return *this;
}
P& operator*() { return *elem;}
P* operator->() { return elem; }
bool operator==(const iter& it) { return elem == it.elem; }
bool operator==(const P& e) { return e == *elem; }
bool operator!=(const iter& it) { return elem != it.elem; }
bool operator!=(const P& e) { return e != *elem; }
private:
P* elem;
P* _base; // can't access members of outer class
size_t _sz; // can't access members of outer class
size_t _rear;
}; // end of iterator class
// ....
IteratorForwQueue begin() { return IteratorForwQueue(_elems + _front, _size, _rear); }
IteratorForwQueue end() { return IteratorForwQueue(nullptr, 0, 0); }
const IteratorForwQueue cbegin() const { return IteratorForwQueue(_elems + _front, _size); }
const IteratorForwQueue cend() const { return IteratorForwQueue(_elems + _rear, _size); }
BTW, it would be better to have a pointer back to the original datastructure, make the iterator a friend class and fetch _base, _sz and _rear on demand.
I have a problem with a const iterator because I try to iterate an array of
pointers but when I try to print it, it returns the array that the first
pointer points at. How can I fix it?
The first array is an array of T and the second array is an array of pointers
to the first array:
class const_iterator {
public:
typedef std::forward_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* pointer;
typedef const T& reference;
const_iterator() : ptr(0) { }
const_iterator(const const_iterator &other) : ptr(other.ptr) { }
const_iterator& operator=(const const_iterator &other) {
ptr = other.ptr;
return *this;
}
~const_iterator() { }
reference operator*() const {
return *ptr;
}
pointer operator->() const {
return ptr;
}
const_iterator operator++(int) {
const_iterator tmp(ptr);
++ptr;
return tmp;
}
const_iterator& operator++() {
++ptr;
return *this;
}
bool operator==(const const_iterator &other) const {
return other.ptr==ptr;
}
bool operator!=(const const_iterator &other) const {
return other.ptr!=ptr;
}
private:
const T *ptr;
friend class SortedArray;
const_iterator(const T*p) : ptr(p){ }
};
const_iterator begin() const {
return const_iterator(*Array);
}
const_iterator end() const {
return const_iterator(*Array+index);
}
I wrote this Vector class and one nested Iterator class and one const_Iterator class, now I have to secure my Vector so my Iterator doesn't point beyond .end() with for instance my operator ++ method and to throw an exception if i try.
so in my iterator class I cannot access .end() because its a vector method. so I was thinking, instead of pointing on values in my Iterator class I point on the whole vector but i cannot access .end() with a Vector* .
Am I on the right way to the solution and if I am how can I pass my Vector so I can use it in the way I intend to?
class Vector{
public:
using value_type= double;
using size_type= size_t;
using difference_type= ptrdiff_t;
using reference = double&;
using const_reference= const double&;
using pointer = double*;
using const_pointer= const double*;
using iterator = double*;
using const_iterator= const double*;
private:
size_t sz;
size_t max_sz;
double* values=nullptr;
class const_Iterator{
public:
using value_type = double;
using difference_type = ptrdiff_t;
using reference = double&;
using pointer = double*;
using iterator_category = std::forward_iterator_tag;
private:
double* ptr;
size_t cnt;
public:
const_Iterator(double* p){
ptr=p;
cnt=0;
}
const_Iterator& operator++ () {
ptr++;
cnt = 0;
return *this;
}
bool operator==(const const_Iterator& rop)const {
return this->ptr == rop.ptr;
}
bool operator!=(const const_Iterator& rop)const {
return this->ptr != rop.ptr;
}
const double operator* () const {
return *ptr;
}
friend Vector::difference_type operator-(const Vector::const_Iterator& lop,const Vector::const_Iterator& rop) {
return lop.ptr-rop.ptr;
}
};
class Iterator{
public:
using value_type = double;
using difference_type = ptrdiff_t;
using reference = double&;
using pointer = double*;
using iterator_category = std::forward_iterator_tag;
private:
double* ptr;
size_t cnt;
public:
Iterator(double* p){
ptr=p;
cnt=0;
}
Iterator& operator++() {
ptr++;
cnt = 0;
return *this;
}
Iterator operator++(int){
Iterator a(ptr);
ptr++;
return a;
}
bool operator==( Iterator& rop) {
return this->ptr != rop.ptr;
}
bool operator!=(const Iterator& rop) {
return this->ptr != rop.ptr;
}
double& operator*() {
return *ptr;
}
operator const_Iterator() const{
return const_Iterator(ptr);
};
};
const_Iterator end() const{return const_Iterator(values+sz);}
const_Iterator begin() const{return const_Iterator(values);}
Iterator begin() { return values; }
Iterator end() { return values + sz; }
size_t min_sz = 5;
Vector();
Vector(size_t);
Vector(const Vector&);
Vector (initializer_list<double> );
void push_back(double);
void reserve(size_t);
void pop_back();
bool empty();
void clear();
Vector& operator=(const Vector&);
const double& operator[] (size_t) const;
double& operator[] (size_t) ;
void fit_to_shrink();
size_t size()const {return sz;}
ostream& print(ostream&) const;
};
Your iterator may look like:
class Iterator{
public:
// ... using type
private:
Vector* parent;
std::size_t index;
public:
Iterator(Vector& v, std::size_t index) : ptr(&v), index(index) {}
Iterator& operator++() {
if (index == parent->size()) {
throw std::runtime_error("++ on end iterator");
}
++index;
return *this;
}
Iterator operator++(int){
Iterator old(*this);
++(*this);
return old;
}
bool operator==(const Iterator& rhs) const {
if (parent != rhs.parent) {
throw std::runtime_error("You compare iterator of different containers");
}
return index == rhs.index;
}
bool operator!=(const Iterator& rop) const { return !(*this == rhs); }
double& operator*() { return parent->at(index); } // `at` throws on invalid index
// ...
};
And your vector:
Iterator Vector::begin() { return Iterator(this, 0);}
Iterator Vector::end() { return Iterator(this, size());}
I'm trying to make the iterator work properly, and for the inequality i != a.end().
I get the error
no know conversion from argument 2 from 'const a3::vector<int>::iterator' to 'const a3::vector<int>&
for the friend function. I need the function to check if the iterator is not equal to vector.end() and am unsure how I would do it.
Class
#include <iostream>
using std::cout;
using std::endl;
namespace a3
{
template <typename T>
class vector
{
public:
class iterator {
public:
int index_;
vector* a_;
iterator() : index_(-1), a_(0) {}
iterator(int index, vector* a) : index_(index), a_(a) {}
iterator& operator=(const iterator& itr)
{
a_ = itr.a_;
index_ = itr.index_;
return *this;
}
iterator& next() {
index_++;
return *this;
}
iterator& operator++() {
return next();
}
int& operator*() { return (*a_)[index_]; }
};
private:
T* mem_;
int sz_;
public:
vector(int sz) : sz_(sz), b_(0, this), e_(sz, this)
{
mem_ = new T[sz];
}
~vector() { delete[] mem_; }
const T& operator[](T i) const { return mem_[i]; }
T& operator[](T i) { return mem_[i]; }
const int& get_size() const { return sz_; }
const iterator& begin() { return b_; }
const iterator& end() { return e_; }
friend bool operator!=(const iterator& itr1, const vector<T>& vec1)
{
return !(itr1.index_ == vec1.end);
}
private:
iterator b_;
iterator e_;
};
}
Main Function
#include "a3_vector.cpp"
int main(int argc, char** argv)
{
using namespace a3;
vector<int> a(10); // allocate an int array of size 10
for (int i=0; i<10; ++i) a[i] = i*2;
// a now looks as follows
//0,2,4,6,8,10,12,14,16,18
// prints the content of the array
vector<int>::iterator i;
for (i = a.begin(); i != a.end(); i.next()) {
cout << *i << endl;
}
}
This is fundamentally wrong:
friend bool operator!=(const iterator& itr1, const vector<T>& vec1)
Iterator comparisons should compare iterators. What you want are comparison operators that look like this:
friend bool operator!=(const iterator& itr1, const iterator& itr2);
friend bool operator==(const iterator& itr1, const iterator& itr2);
After all, that's what this expression is trying to do:
i != a.end()
You're trying to compare two iterators. The error is just trying to convert a.end() to a const vector<T>&, since that's the match that it found for !=. Simply fix != to take an iterator as the second argument and you'll be fine.