Creating own iterator for double vectors - c++

I am a bit new at c++, so the question may be without any meaning, so, sorry about that in advance.
So, i have a class of hashtable, my hashtable is vector of vectors, it means that i used
std::vector<std::vector<std::string> > htable;
My task is - create own iterator with operation ++, --, -> and *. I wrote this
class hashTable
{
public:
hashTable(int size);
~hashTable();
void add(std::string s);
bool inHash(std::string s);
void deletestr(std::string s);
void printall();
int maxcoll();
private:
std::vector<std::vector<std::string> > htable;
std::vector<std::vector<std::string> > newhtable;
int hfunc(std::string s);
void reallocate();
int M;
int teksize;
int issame(std::string a, std::string b);
class myiterator{
myiterator();
myiterator operator*();
myiterator operator++();
myiterator operator--();
myiterator operator->();
};
myiterator begin() {return htable.begin()}
myiterator end() {return htable.end()}
};
I think, that i understand what the interator is, but now i suppose that i was wrong, so when i try to compile this, there is a mistake in lines
myiterator begin() {return htable.begin()}
myiterator end() {return htable.end()}
/Users/ratkke/Programms/c++/mipt/tasks/#5/myhash.cpp:37:29: error: no viable conversion from 'iterator' (aka '__wrap_iter') to 'hashTable::myiterator'
myiterator begin() {return htable.begin()}
^~~~~~~~~~~~~~
/Users/ratkke/Programms/c++/mipt/tasks/#5/myhash.cpp:29:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'iterator' (aka '__wrap_iter') to 'const hashTable::myiterator &' for 1st argument
class myiterator{
And i don't know why. Also, can you tell me about realisation of iterator(or just link to article) for iterator for vectors, because i can't understand how i must implement all this operators.
Thank you in advance.

You need to implement your myiterator. There are lots of way to do that, but at very least you must add something to myiterator. For instance
class myiterator{
public:
myiterator();
myiterator(std::vector<std::vector<std::string> >& v, int ii, int jj) :
vec(v), i(ii), j(jj) {}
std::string operator*();
myiterator& operator++(); // prefix operator
myiterator operator++(int); // postfix operator
myiterator& operator--(); // prefix operator
myiterator operator--(int); // postfix operator
std::string* operator->();
private:
std::vector<std::vector<std::string> >& vec; // the vector we are iterating over
int i; // the position in the vector (first dimension)
int j; // the position in the vector (second dimension)
};
myiterator begin() {return myiterator(htable, 0, 0);}
Lots of other ways to do it, and the above may not be exactly what you want, but hopefully this gives you the idea, myiterator must have some data members that hold the vector being iterated over and the position reached so far.
Also note the return type of operator* is wrong, it should (presumably) be std::string. Some of the other operators don't look right either, I've put what I think is correct in the code.

Related

C++: copy constructor for iterators

I am currently in the process of refreshing my knowledge of the language, and have found the following example here defining an iterator class. Am I mistaken in saying that the way the copy constructor in this iterator is defined in such a way that it will only create a shallow copy or am I missing something?
Wouldn't this create problems when used given that the class attribute is an int pointer?
Thanks.
// std::iterator example
#include <iostream> // std::cout
#include <iterator> // std::iterator, std::input_iterator_tag
class MyIterator : public std::iterator<std::input_iterator_tag, int>
{
int* p;
public:
MyIterator(int* x) :p(x) {}
MyIterator(const MyIterator& mit) : p(mit.p) {}
MyIterator& operator++() {++p;return *this;}
MyIterator operator++(int) {MyIterator tmp(*this); operator++(); return tmp;}
bool operator==(const MyIterator& rhs) const {return p==rhs.p;}
bool operator!=(const MyIterator& rhs) const {return p!=rhs.p;}
int& operator*() {return *p;}
};
The concept of "deep" copying only applies to objects owning another object through some kind of reference (e.g. a pointer). The iterator uses its value (the pointer) in an non-owning fashion, and so copying the value of that pointer is enough to maintain the semantics of the class.
In fact (as pointed by Caleth in the comments), in this case the compiler would generate precisely this copy-ctor by default, so you don't even have to write it.
If your copy-ctor actually copied the data being pointed to, it wouldn't be a very good iterator, because you'd then lose the access to the object you wanted to iterate.

How can I use a overloaded const_iterator inside a class?

I'm doing a University project in C++, whose purpose is to learn how to use the diferent STL containers and their iterators.
In my program, I have a class with a set:
class ConjuntoDeLetras{
private:
set<Letra> letras;
public:
ConjuntoDeLetras();
···
};
Inside the class, I have two nested class, iterator and const_iterator. (I don't know if it's the best way to make class iterators, but the teacher tell us that we need to do at this way):
class iterator{
private:
set<Letra>::iterator it;
public:
iterator();
Letra operator*();
ConjuntoDeLetras::iterator& operator++();
ConjuntoDeLetras::iterator& operator+=(int num);
bool operator==(const ConjuntoDeLetras::iterator &i);
bool operator!=(const ConjuntoDeLetras::iterator &i);
friend class ConjuntoDeLetras;
};
class const_iterator{
private:
set<Letra>::const_iterator it;
public:
const_iterator();
Letra operator*();
ConjuntoDeLetras::const_iterator& operator++();
ConjuntoDeLetras::const_iterator& operator+=(int num);
bool operator==(const ConjuntoDeLetras::const_iterator &i);
bool operator!=(const ConjuntoDeLetras::const_iterator &i);
friend class ConjuntoDeLetras;
};
Both iterator class methods works well. In ConjuntoDeLetras class we have the begin and end methods:
ConjuntoDeLetras::iterator begin();
ConjuntoDeLetras::const_iterator begin() const;
ConjuntoDeLetras::iterator end();
ConjuntoDeLetras::const_iterator end() const;
The problem is here. When I'm going to use the const_iterator we have problems:
ConjuntoDeLetras::const_iterator itL;
for(itL=L.begin(); itL!=L.end(); ++itL){
CantidadLetras aux;
aux.frecuenciaAbsoluta = 0;
aux.frecuenciaRelativa = 0;
aux.letra = (*itL).getLetra();
salida.push_back(aux);
}
When I execute this code the compiler says that I don't have operator= for const_iterator to iterator. I know the reason of the problem, it's because the object L is a not const variable and uses the normal iterator begin() and end(). I thought about removing the final const of the functions but I can't overload the function only with the return type. I don't know what is the best solution. Here is the compiler error:
error: no match for ‘operator=’ (operand types are ‘ConjuntoDeLetras::const_iterator’ and ‘ConjuntoDeLetras::iterator’)
for(itL=L.begin(); itL!=L.end(); ++itL){
^
And the same error with the end().
You are missing the other ++ operator and the required typedefs to be an iterator.
Plus, you need =default copy/move/assignments.
Finally you need a converting constructor from your iterator to your const_iterator.
Optionaly add two const_iterator::operator=(iterator) overloads (copy assign and move assign), plus const_iterator::operator==(iterator const&) and iterator==const_iterator similarly.

C++, having issues using const_iterator to make operator=

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.

Custom iterator of 2D vector [duplicate]

I am a bit new at c++, so the question may be without any meaning, so, sorry about that in advance.
So, i have a class of hashtable, my hashtable is vector of vectors, it means that i used
std::vector<std::vector<std::string> > htable;
My task is - create own iterator with operation ++, --, -> and *. I wrote this
class hashTable
{
public:
hashTable(int size);
~hashTable();
void add(std::string s);
bool inHash(std::string s);
void deletestr(std::string s);
void printall();
int maxcoll();
private:
std::vector<std::vector<std::string> > htable;
std::vector<std::vector<std::string> > newhtable;
int hfunc(std::string s);
void reallocate();
int M;
int teksize;
int issame(std::string a, std::string b);
class myiterator{
myiterator();
myiterator operator*();
myiterator operator++();
myiterator operator--();
myiterator operator->();
};
myiterator begin() {return htable.begin()}
myiterator end() {return htable.end()}
};
I think, that i understand what the interator is, but now i suppose that i was wrong, so when i try to compile this, there is a mistake in lines
myiterator begin() {return htable.begin()}
myiterator end() {return htable.end()}
/Users/ratkke/Programms/c++/mipt/tasks/#5/myhash.cpp:37:29: error: no viable conversion from 'iterator' (aka '__wrap_iter') to 'hashTable::myiterator'
myiterator begin() {return htable.begin()}
^~~~~~~~~~~~~~
/Users/ratkke/Programms/c++/mipt/tasks/#5/myhash.cpp:29:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'iterator' (aka '__wrap_iter') to 'const hashTable::myiterator &' for 1st argument
class myiterator{
And i don't know why. Also, can you tell me about realisation of iterator(or just link to article) for iterator for vectors, because i can't understand how i must implement all this operators.
Thank you in advance.
You need to implement your myiterator. There are lots of way to do that, but at very least you must add something to myiterator. For instance
class myiterator{
public:
myiterator();
myiterator(std::vector<std::vector<std::string> >& v, int ii, int jj) :
vec(v), i(ii), j(jj) {}
std::string operator*();
myiterator& operator++(); // prefix operator
myiterator operator++(int); // postfix operator
myiterator& operator--(); // prefix operator
myiterator operator--(int); // postfix operator
std::string* operator->();
private:
std::vector<std::vector<std::string> >& vec; // the vector we are iterating over
int i; // the position in the vector (first dimension)
int j; // the position in the vector (second dimension)
};
myiterator begin() {return myiterator(htable, 0, 0);}
Lots of other ways to do it, and the above may not be exactly what you want, but hopefully this gives you the idea, myiterator must have some data members that hold the vector being iterated over and the position reached so far.
Also note the return type of operator* is wrong, it should (presumably) be std::string. Some of the other operators don't look right either, I've put what I think is correct in the code.

constructors and conversions of classes

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);
}