I have 2 classes:
class iterator {
Node<K,V>* n;
public:
iterator(){
std::cout<<"new empty iterator"<<std::endl;
};
iterator(const iterator& iter):n(iter.n){
std::cout<<"copy iterator"<<std::endl;
}
explicit iterator(Node<K,V>* nodePtr):n(nodePtr) {
std::cout<<"create iterator with Node Ptr"<<std::endl;
}
iterator& operator=(const iterator& iter);
void operator++();
Node<K,V>& operator*();
bool operator!=(const iterator& iter);
K& operator[](const Key& k)const;
V& operator[](const Val& v)const;
Node<K,V>* getNodePtr()const{
std::cout<<"get Node Ptr"<<std::endl;
return n;
}
friend class Map;
};
class const_iterator :public iterator {
const Node<K,V>* n;
public:
const_iterator(){
std::cout<<"new empty const_iterator"<<std::endl;
};
const_iterator(const iterator& iter):
n(iter.getNodePtr()){
std::cout<<"convert"<<std::endl;
}
const_iterator(const const_iterator& iter):n(iter.n){}
explicit const_iterator(const Node<K,V>* node):n(node){}
const_iterator& operator=(const const_iterator& iter){
n = iter.n;
return *this;
}
const Node<K,V>& operator*(){
return *n;
}
friend class Map;
};
iterator begin()const{
return iterator(firstKey);
}
iterator end()const{
return iterator(dummyKey);
}
I want it to make an automatic conversion between the 2 classes using:
const_iterator(const iterator& iter):
n(iter.getNodePtr()){
std::cout<<"convert"<<std::endl;
}
to do something like this for example:
Map<int,int>::const_iterator it = m.begin();
now, the thing is, that this constructor calls for some reason iterator(); in the first class and I can't figure out why.
I know begin() and end() have some standart versions, but I can't use any of it here. I also can't make Map to be const, or write a conversion function.
any help?
You've made iterator a base class of const_iterator, so an iterator constructor will (and should) be called as part of constructing a const_iterator.
If you will define data storage as
const Map<int, int> data;
instead of
Map<int, int> data;
const version of begin() and end() will be invoked.
Also, C++11 standard containers add cbegin() and cend() for that purpose. You could re-difine it as follows:
const_iterator cbegin()const{
return const_iterator(firstKey);
}
const_iterator cend()const{
return const_iterator(dummyKey);
}
Related
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]);
}
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);
}
There is a compilation error which occurs when I write the following:
const_iterator it = cp.begin();
const_iterator is my own class for const iterator.
cp is an object of a class ConjuntoPreguntas (see below).
The error is:
mainprueba.cpp:30:6: error: no match for ‘operator=’ (operand types are ‘ConjuntoPreguntas::const_iterator’ and ‘ConjuntoPreguntas::iterator’)
cit = CP.begin();
^
mainprueba.cpp:30:6: note: candidate is:
In file included from mainprueba.cpp:2:0:
conjuntopreguntas.h:258:21: note: ConjuntoPreguntas::const_iterator& ConjuntoPreguntas::const_iterator::operator=(const ConjuntoPreguntas::const_iterator&)
const_iterator& operator=(const const_iterator& cit){
^
conjuntopreguntas.h:258:21: note: no known conversion for argument 1 from ‘ConjuntoPreguntas::iterator’ to ‘const ConjuntoPreguntas::const_iterator&’
The code:
class ConjuntoPreguntas{
private:
map<int,Pregunta> preguntas;
public:
class const_iterator;
class iterator{
private:
map<int,Pregunta>::iterator it;
public:
iterator & operator++(){
++it;
}
iterator & operator--(){
--it;
}
pair<const int,Pregunta> &operator *(){
return *it;
}
bool operator ==(const iterator &i){
return i.it==it;
}
bool operator !=(const iterator &i){
return i.it!=it;
}
friend class ConjuntoPreguntas;
friend class const_iterator;
};
class const_iterator{
private:
map<int,Pregunta>::iterator it;
public:
const_iterator(){
}
const_iterator & operator++(){
++it;
}
const_iterator & operator--(){
--it;
}
pair<const int,Pregunta> &operator *(){
return *it;
}
bool operator ==(const const_iterator &i){
return i.it==it;
}
bool operator !=(const const_iterator &i){
return i.it!=it;
}
const_iterator& operator=(const const_iterator& cit){
}
friend class ConjuntoPreguntas;
};
iterator begin(){
iterator i;
i.it=preguntas.begin();
return i;
}
iterator end(){
iterator i;
i.it=preguntas.end();
return i;
}
/* other code, irrelevant to the problem */
};
If anyone can help me, I will be very grateful.
Your most immediate problem is because you don't have a const version of begin:
const_iterator begin() const
{
const_iterator i;
i.it = preguntas.begin();
return i;
}
But then also your const_iterator class uses map's iterator which is going to result in another problem.
If you're writing a container-looking class, there's nothing for it but to write const-correct iterator and const_iterator classes and provide the const-correct members.
If however you are NOT writing a container, you may not want to do this. The best case is to provide a container-agnostic interface to the class, where for example you provide meaningful names rather than direct container access. Alternately provide const-only access via the map const_iterator (don't write your own iterator class).
If you want to fully encapsulate std container inside your class (daunting and usually unneccessary task) you need to make sure you also define all conversions. In particlar, standard container iterators have a constructor which creates const_iterator from iterator (but not the other way around!). You will have to create it yourselfa as well.
However, a much better design choice would be to simply expose the member map variable.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I have a custom container that I have been using for many years without issues. Recently I found out that if I define iterators for my container, I can effectively use all of the algorithms defined in <algorithm>. Not only that, it seems that thrust library (basically think CUDA version of STL for Nvidia GPUs) heavily uses iterators and I am hoping that by using them I'll be able to use that library as well.
Anyway, since this is my first try at writing my own iterators, I thought I post what I have here to ask for further assistance and make sure what I'm doing is right. So, I wrote a little array class that supports both iterator and const_iterator classes. I ran my class with a bunch of different STL algorithms and all seem to work fine but that does not necessarily mean I've got everything right! In particular, is there any operator that I miss for my iterators?
Have I defined extra unnecessary ones? Also, since most of iterator and const_iterator look similar, is there a way to prevent duplication?
I'm open to suggestions and improvements :)
Live example: http://ideone.com/7YdiQY
#include <cstddef>
#include <iostream>
#include <iterator>
#include <algorithm>
template<typename T>
class my_array{
T* data_;
std::size_t size_;
public:
// ---------------------------------
// Forward declaration
// ---------------------------------
class const_iterator;
// ---------------------------------
// iterator class
// ---------------------------------
class iterator: public std::iterator<std::random_access_iterator_tag, T>
{
public:
iterator(): p_(NULL) {}
iterator(T* p): p_(p) {}
iterator(const iterator& other): p_(other.p_) {}
const iterator& operator=(const iterator& other) {p_ = other.p_; return other;}
iterator& operator++() {p_++; return *this;} // prefix++
iterator operator++(int) {iterator tmp(*this); ++(*this); return tmp;} // postfix++
iterator& operator--() {p_--; return *this;} // prefix--
iterator operator--(int) {iterator tmp(*this); --(*this); return tmp;} // postfix--
void operator+=(const std::size_t& n) {p_ += n;}
void operator+=(const iterator& other) {p_ += other.p_;}
iterator operator+ (const std::size_t& n) {iterator tmp(*this); tmp += n; return tmp;}
iterator operator+ (const iterator& other) {iterator tmp(*this); tmp += other; return tmp;}
void operator-=(const std::size_t& n) {p_ -= n;}
void operator-=(const iterator& other) {p_ -= other.p_;}
iterator operator- (const std::size_t& n) {iterator tmp(*this); tmp -= n; return tmp;}
std::size_t operator- (const iterator& other) {return p_ - other.p_;}
bool operator< (const iterator& other) {return (p_-other.p_)< 0;}
bool operator<=(const iterator& other) {return (p_-other.p_)<=0;}
bool operator> (const iterator& other) {return (p_-other.p_)> 0;}
bool operator>=(const iterator& other) {return (p_-other.p_)>=0;}
bool operator==(const iterator& other) {return p_ == other.p_; }
bool operator!=(const iterator& other) {return p_ != other.p_; }
T& operator[](const int& n) {return *(p_+n);}
T& operator*() {return *p_;}
T* operator->(){return p_;}
private:
T* p_;
friend class const_iterator;
};
// ---------------------------------
// const_iterator class
// ---------------------------------
class const_iterator: public std::iterator<std::random_access_iterator_tag, T>
{
public:
const_iterator(): p_(NULL) {}
const_iterator(const T* p): p_(p) {}
const_iterator(const iterator& other): p_(other.p_) {}
const_iterator(const const_iterator& other): p_(other.p_) {}
const const_iterator& operator=(const const_iterator& other) {p_ = other.p_; return other;}
const const_iterator& operator=(const iterator& other) {p_ = other.p_; return other;}
const_iterator& operator++() {p_++; return *this;} // prefix++
const_iterator operator++(int) {const_iterator tmp(*this); ++(*this); return tmp;} // postfix++
const_iterator& operator--() {p_--; return *this;} // prefix--
const_iterator operator--(int) {const_iterator tmp(*this); --(*this); return tmp;} // postfix--
void operator+=(const std::size_t& n) {p_ += n;}
void operator+=(const const_iterator& other) {p_ += other.p_;}
const_iterator operator+ (const std::size_t& n) const {const_iterator tmp(*this); tmp += n; return tmp;}
const_iterator operator+ (const const_iterator& other) const {const_iterator tmp(*this); tmp += other; return tmp;}
void operator-=(const std::size_t& n) {p_ -= n;}
void operator-=(const const_iterator& other) {p_ -= other.p_;}
const_iterator operator- (const std::size_t& n) const {const_iterator tmp(*this); tmp -= n; return tmp;}
std::size_t operator- (const const_iterator& other) const {return p_ - other.p_;}
bool operator< (const const_iterator& other) const {return (p_-other.p_)< 0;}
bool operator<=(const const_iterator& other) const {return (p_-other.p_)<=0;}
bool operator> (const const_iterator& other) const {return (p_-other.p_)> 0;}
bool operator>=(const const_iterator& other) const {return (p_-other.p_)>=0;}
bool operator==(const const_iterator& other) const {return p_ == other.p_; }
bool operator!=(const const_iterator& other) const {return p_ != other.p_; }
const T& operator[](const int& n) const {return *(p_+n);}
const T& operator*() const {return *p_;}
const T* operator->() const {return p_;}
private:
const T* p_;
};
my_array()
: data_(NULL), size_(0)
{}
my_array(std::size_t size)
: data_(new T[size]), size_(size)
{}
my_array(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
}
my_array(const const_iterator& first, const const_iterator& last){
size_ = last - first;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = first[i];
}
~my_array(){
delete [] data_;
}
const my_array<T>& operator=(const my_array<T>& other){
size_ = other.size_;
data_ = new T[size_];
for (std::size_t i = 0; i<size_; i++)
data_[i] = other.data_[i];
return other;
}
const T& operator[](std::size_t idx) const {return data_[idx];}
T& operator[](std::size_t& idx) {return data_[idx];}
std::size_t size(){return size_;}
iterator begin(){ return iterator(data_); }
iterator end() { return iterator(data_+size_); }
const_iterator begin() const{ return const_iterator(data_); }
const_iterator end() const { return const_iterator(data_+size_);}
};
template<typename T>
void print(T t) {
std::cout << t << std::endl;
}
int main(){
// works!
int list [] = {1, 3, 5, 2, 4, 3, 5, 10, 10};
my_array<int> a(list, list+sizeof(list)/sizeof(int));
// works!
for (my_array<int>::const_iterator it = a.begin(), end = a.end();
it != end; ++it)
std::cout << ' ' << *it;
std::cout << std::endl;
// works!
std::for_each(a.begin(), a.end(), print<int>);
std::cout << std::endl;
// works!
my_array<int> b(a.size());
std::copy(a.begin(), a.end(), b.begin());
// works!
my_array<int>::iterator end = std::remove(a.begin(), a.end(), 5);
std::for_each(a.begin(), end, print<int>);
std::cout << std::endl;
// works!
std::random_shuffle(a.begin(), end);
std::for_each(a.begin(), end, print<int>);
std::cout << std::endl;
// works!
std::cout << "Counts of 3 in array = " << std::count(a.begin(), end, 3) << std::endl << std::endl;
// works!
std::sort(a.begin(), end);
std::for_each(a.begin(), end, print<int>);
std::cout << std::endl;
// works!
if (!std::binary_search(a.begin(), a.end(), 5))
std::cout << "Removed!" << std::endl;
return 0;
}
boost iterator provides a framework to create stl-compliant iterators and to adapt existing ones.
It allows you to focus on the functionality and generates all necessary traits, typedefs for you.
iterator and const_iterator creation without much code-duplication is supported as well.
The Boost iterator_adaptor can greatly simplify your code. The documentation has e.g. this example for a linked list iterator
template <class Value>
class node_iter
: public boost::iterator_adaptor<
node_iter<Value> // Derived
, Value* // Base
, boost::use_default // Value
, boost::forward_traversal_tag // CategoryOrTraversal
>
{
private:
struct enabler {}; // a private type avoids misuse
public:
node_iter()
: node_iter::iterator_adaptor_(0) {}
explicit node_iter(Value* p)
: node_iter::iterator_adaptor_(p) {}
template <class OtherValue>
node_iter(
node_iter<OtherValue> const& other
, typename boost::enable_if<
boost::is_convertible<OtherValue*,Value*>
, enabler
>::type = enabler()
)
: node_iter::iterator_adaptor_(other.base()) {}
private:
friend class boost::iterator_core_access;
void increment() { this->base_reference() = this->base()->next(); }
};
Note that the example only provides a default constructor, a constructor taking a node pointer, a generalized copy constructor that only accepts elements that can be converted to a node pointer, and an increment function. The increment function is an implementation detail that is shared by both operator++() and operator++(int).
All the other boiler-plate is automatically being generated by deriving from boost::iterator_adaptor. That includes all the nested typedef that you could also get from deriving from std::iterator, as well as all the overloaded operators (++, *, ->, ==, !=, advance) and anything else to make it a fully Standard conforming iterator.
By passing a Value const* and using a typedef you can define a const_iterator that reuses all your code with the appropriate modifications. Studying the example now will save you enormously down the road.
I have for homework to make my own abstract class Vector. This vector should have iterator. I make iterator in public part of the Vector. This is my code for iterator:
class iterator {
friend class Vector;
Vector* v_;
int position_;
iterator(Vector* v,int position)
: v_(v),
position_(position)
{}
public:
iterator()
: v_(0),
position_(0)
{}
iterator& operator++() {// pre
position_++;
return *this;
}
iterator operator++(int) {//post
iterator res=*this;
position_++;
return res;
}
T& operator*() {
return v_->buffer_[position_];
}
T* operator->() {
return &buffer_[position_];
}
bool operator==(const iterator& other) const {
return position_ == other.position_;
}
bool operator!=(const iterator& other) const {
return !operator==(other);
}
};
My question is if the operator -> is correct defined.
Thanks
I believe you're really wanting a slightly modified definition that gets the value at the current position of the vector, i.e., return &((*v_)[position_]); if you've overloaded the operator[] of your vector class. Otherwise in order to get access to the buffer_ of your vector, you have to dereference the vector first in order to get to the buffer, i.e., return &(v_->buffer[position_]);