473,397 Members | 2,056 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

How to make an iterator for my Matrix class

Hi, i'm making a matrix class, here is my code:

Expand|Select|Wrap|Line Numbers
  1. #ifndef MATRICE_H
  2. #define MATRICE_H
  3.  
  4. #include <iostream>
  5.  
  6. template <class T> class matrice {
  7.  
  8.  public:
  9.  
  10.   typedef int sizet;
  11.   typedef T valuet;
  12.  
  13.  matrice(): _data(0), _row(0), _col(0) {}; //costruttore default
  14.  
  15.   matrice(sizet rw, sizet cl) { //causa errore in valgrind
  16.     _data=new valuet*[rw];
  17.     for(sizet i=0;i<rw;i++)
  18.       _data[i]=new valuet[cl];
  19.     _row=rw;
  20.     _col=cl;
  21.   }
  22.  
  23.   matrice(sizet rw, sizet cl, valuet value) {
  24.     _data=new valuet*[rw];
  25.     for(sizet i=0;i<rw;i++) {
  26.       _data[i]=new valuet[cl];
  27.       for(sizet j=0;j<cl;j++)
  28.     _data[i][j]=value;
  29.     }
  30.     _row=rw;
  31.     _col=cl;
  32.   }
  33.  
  34.   matrice(const matrice &other) { //copy constructor
  35.     _row=other._row;
  36.     _col=other._col;
  37.     _data=new valuet*[_row];
  38.     for(sizet i=0;i<_row;i++) {
  39.       _data[i]=new valuet[_col];
  40.       for(sizet j=0;j<_col;j++)
  41.     _data[i][j]=other._data[i][j];
  42.     }
  43.   }
  44.  
  45.   ~matrice() { //distruttore
  46.     for (sizet i=0;i<_row;i++)
  47.       delete[] _data[i];
  48.     delete[] _data;
  49.     _data=0;
  50.   }
  51.  
  52.   matrice& operator=(const matrice &other){ //operatore =
  53.     if (this!=&other) {
  54.       for (sizet i=0;i<_row;i++)
  55.     delete[] _data[i];
  56.       delete[] _data;
  57.       _row=other._row;
  58.       _col=other._col;
  59.       _data=new int*[_row];
  60.       for(sizet i=0;i<_row;i++) {
  61.     _data[i]=new int[_col];
  62.     for(sizet j=0;j<_col;j++)
  63.       _data[i][j]=other._data[i][j];
  64.       }
  65.     }
  66.     return *this;
  67.   }
  68.  
  69.   sizet getSize() const {
  70.     return _row*_col;
  71.   }
  72.  
  73.   sizet getRow() const {
  74.     return _row;
  75.   }
  76.  
  77.   sizet getCol() const {
  78.     return _col;
  79.   }
  80.  
  81.   valuet getValue(sizet x, sizet y) const {
  82.     return _data[x][y];
  83.   }
  84.  
  85.   void setValue(sizet x, sizet y, valuet value) {
  86.     _data[x][y]=value;
  87.   }
  88.  
  89.   valuet &operator()(sizet x, sizet y) { //lettura e scrittura
  90.     return _data[x][y];
  91.   }
  92.  
  93.   const valuet &operator()(sizet x, sizet y) const { //solo lettura
  94.     return _data[x][y];
  95.   }
  96.  
  97.  private:
  98.  
  99.   valuet **_data;
  100.   sizet _row;
  101.   sizet _col;
  102.  
  103. };
  104.  
  105. struct is_even {
  106.   inline bool operator()(const int value) const {
  107.     return value%2==0 ? true : false;
  108.   }
  109. };
  110.  
  111. struct is_letter {
  112.   inline bool operator()(const char value) const {
  113.     return (value>='a' && value<='z') || (value>='A' && value<='Z') ? true : false;
  114.   }
  115. };
  116.  
  117. template <class T>
  118. std::ostream &operator<<(std::ostream &left, const matrice<T> &right) {
  119.   for(typename matrice<T>::sizet i=0;i<right.getRow();i++){
  120.     for(typename matrice<T>::sizet j=0;j<right.getCol();j++)
  121.       left<<right.getValue(i,j)<<" ";
  122.     left<<std::endl;
  123.   }
  124.   return left;
  125. }
  126.  
  127. template <class T, class F> 
  128. bool verify(const matrice<T> &mat, const F &fun) {
  129.   bool ret=true;
  130.   for(typename matrice<T>::sizet i=0;i<mat.getRow();i++)
  131.     for(typename matrice<T>::sizet j=0;j<mat.getCol();j++)
  132.       ret=ret && fun(mat.getValue(i,j));
  133.   return ret;
  134. }
  135.  
  136. #endif
This is a project for school, now is required to implement an iterator that goes through every element of the matrix (first all the element of the first row, then all the element of the second row, and so on)
i made a class iterator with the ++ operator that just increment the pointer, while begin() return the first element of the matrix and end() the last, but doing so it reads all the element of the matrix but also other data between the rows, how can i fix it?
please help me!
ps: sorry for my english but i'm italian!
Jan 29 '10 #1
11 7241
Banfa
9,065 Expert Mod 8TB
The data in your matrix is not contiguous, that is you do not allocate it as a single block of data but rather you allocate an array of pointers and then to each pointer to allocate an array of the value types.

That means that when you are at the end of a row of data you have no guarantee (and in fact it is very unlikely) that the start of the next row is in the next memory location.

You have a couple of options
  1. Your iterators ++ operator needs to be more complex. When the operator runs it needs to detect if it is at the end of the current row and it is start using the next row explicitly.
  2. You data structure needs to be less complex. Rather than an array of pointers to arrays of value types you could simple implement this as a one single dimensioned array of value types. You use the row and column to calculate the correct index in this array for any given cell. Direct cell access is marginally more complex but data management and iterators complexity are both reduced.
Jan 29 '10 #2
thanks a lot for your answer, unfortunately i cannot use the second option cause the teacher asked us to not implement the matrix in that way
I have already tried the first option, but i wasn't able to make it works...cause i would need to compare my pointer with _data[row][_col-1], then if they are the same skip to _data[row+1][0], else i would just increment my pointer
The problem is that i dont understand how can i make _data of an istance of my class matrix available in my class iterator, so that i can compare it to my pointer...can i pass it by reference in the constructor of the iterator?would it work?

ps:again, sorry for my english and thanks for your help!
Jan 29 '10 #3
weaknessforcats
9,208 Expert Mod 8TB
that i dont understand how can i make _data of an istance of my class matrix available in my class iterator, so that i can compare it to my pointer...can i pass it
Just look in the C++ vector header and see how iterators are implemented in the Standard Library. You will find the iterator for a class is itself a class nested inside the class it iterates.

Expand|Select|Wrap|Line Numbers
  1. class A
  2. {
  3.     public:
  4.  
  5.         class Iterator
  6.         {
  7.  
  8.         };
  9. };
  10.  
  11. main()
  12. {
  13.    A::Iterator obj;   //obj is an iterator for A
  14. }
Next, I don't see what your problem is. a) You have an array of pointers so
_data[r] os a row of your matrix. Then b) you allocated the columns so that _data[r][c] is an element of your matrix. This is all fine.

What's not fine is _data[r][c- offset] to position you to an element in another row. You will need to use manually adjust the row index r and then position to the correct element.

I really recommend you read Arrays Revealed in the C++ Insights to really see why this so.
Jan 29 '10 #4
WARNING:i know it's a long post (cause there is a lot of code), but i m asking just for a little problem, please try to help me even if it's long cause i really need your help!

ok now i fixed the main problem, now when i try to read or to set all the elements of the matrix it works, but i have another little problem, first of all, here is my class iterator (nested inside class matrice (matrix in italian :P), and the two functions begin() and end() of the class matrice:
Expand|Select|Wrap|Line Numbers
  1.   class iterator {
  2.     friend class const_iterator;
  3.     friend class matrice;
  4.  
  5.  
  6.   public:
  7.     typedef std::forward_iterator_tag iterator_category;
  8.     typedef T valuet;
  9.     typedef ptrdiff_t difference_type;
  10.     typedef T* pointer;
  11.     typedef T& reference;
  12.  
  13.   iterator() : ptr(0),col(0),c(0)  {}
  14.  
  15.   iterator(const iterator &other) : ptr(other.ptr), col(other.col), c(other.c) {}
  16.  
  17.     iterator& operator=(const iterator &other) {
  18.        ptr=other.ptr;
  19.       col=other.col;
  20.       c=other.c;
  21.       return *this;
  22.     }
  23.  
  24.     ~iterator() {}
  25.  
  26.     valuet *operator*() const {
  27.       return *ptr;
  28.     }
  29.  
  30.  
  31.     valuet *operator->() const {
  32.       return *ptr;
  33.     }
  34.  
  35.     bool operator==(const iterator &other) const {
  36.       return ptr==other.ptr;
  37.     }
  38.  
  39.     bool operator!=(const iterator &other) const {
  40.       return !(*this==other);
  41.     }
  42.  
  43.     bool operator==(const const_iterator &other) const {
  44.       return ptr==other.ptr;
  45.     }
  46.  
  47.     bool operator!=(const const_iterator &other) const {
  48.       return !(*this==other);
  49.     }
  50.  
  51.     iterator &operator++() {
  52.       c++;
  53.       if (c==col) {
  54.         *ptr=*ptr-(col-1);
  55.     ++ptr;
  56.     c=0;
  57.     } else
  58.       ++(*ptr);
  59.       return *this;
  60.     }
  61.  
  62.     iterator operator++(int) {
  63.       iterator tmp(ptr,riga,col,c);
  64.       c++;
  65.       if (c==col) {
  66.     *ptr=*ptr-(col-1);
  67.     ++ptr;
  68.     c=0;
  69.       }
  70.       else
  71.     ++(*ptr);
  72.       return tmp;
  73.     }
  74.  
  75.   private:
  76.     valuet **ptr;
  77.     int col;
  78.     int c;
  79.     iterator(valuet **p,int cl) : ptr(p), col(cl), c(0) {}
  80.     iterator(valuet **p, int cl, int co) : ptr(p), riga(po), col(cl), c(co) {}
  81.  
  82.   };//iteratorRow
  83.  
  84.  
  85.   iterator begin() {
  86.     return iterator(_data,_col);
  87.   }
  88.  
  89.  
  90.   iterator end() {
  91.     return iterator(_data+_row,_col);
  92.   }
  93.  
so now it works when i try to run something like this:
Expand|Select|Wrap|Line Numbers
  1.   matrice<int>::iterator it,ite;
  2.  for (it=b.begin(),ite=b.end(); it!=ite;++it){ //b is a matrix of int
  3.    std::cout << **it << " ";
  4.    **it=1;
  5. }
  6.  
it writes all the elements of the matrix (skipping values between rows), and it sets all the elements to 1

but i have a problem if i try to run something like this:
Expand|Select|Wrap|Line Numbers
  1. it=b.begin();
  2.   it++;
  3.   ite=++it;
  4.   it++;++it;
  5.   matrice<int>::iterator iter;
  6.    for (iter=b.end(); ite!=iter;ite++)
  7.    std::cout << **ite << " ";
  8.  
the problem is that when i increment it (it++,++it), also ite is incremented (despite there's no ite++ :/)..i think the problem is with **ptr, that in someways is shared by both iterator, but i cannot make it works...i don't understand how to fix this problem!i'm trying hard but i really need your help!
Feb 4 '10 #5
weaknessforcats
9,208 Expert Mod 8TB
Both of your iterators have the same address in ptr. So when you ++ interator A you use *ptr and update the thing that ptr points at. That's the same object the ptr in your other iterator points at.

Your operator++ must ++ ptr and not *ptr.

For example, in this array:

1 2 3 4 5 6 7 8 9

an iterator pointing at 5 when incremented will point at 6. That is, the iterator contains the address of the specific element and not the address of a pointer to the specific element.

If this array is viewed as:

1 2 3
4 5 6
7 8 9

the address of the element in the iterator is the same since all arrays are really one-dimensional.
Feb 6 '10 #6
but my array is bidimensional (**_data), so when i have:
1 2 3
4 5 6
7 8 9

there are same values between the rows (like a 0 and a 33...but i think they can change :P)
so how can i move from a row to an another without incrementing both *ptr and ptr?
thanks for your answer weaknessforcats, i have to finish this project in a few days but i can't fix this last problem :/ i hope someone can help me!
Feb 7 '10 #7
weaknessforcats
9,208 Expert Mod 8TB
Again I say, there are no multidimensional arrays on C or C++. Everything is one-dimensional. Each element has an address. The array is contiguous. Element 5 is the address of element 0 + 4 x sizeof(the element). It has ot be this way otherwise pointer aritmentic does not work.

An iterator is to point to an element. That is, it contains the address of an element. Not the address of something else.

Your iterator needs to contain a simple pointer to the element.

If your array is "mult-dimensional" it is only becuse you say so. That neing the case you can create code to view the array as multi-dimensional.

You might read the C Forum Insight article Arrays Revealed. What I am saying here is covered in about the last example.
Feb 7 '10 #8
well but as also Banfa said the data in my matrix are not contiguos, so if i have
1 2 3
4 5 6
7 8 9
element 5 will not be the address of element 0 + 4 x sizeof(the element)...if i add sizeof(element) to element 3, i will get a value that is not in the first row, and is not in the second row, it's just between the two rows!
So as Banfa said i have to make my operator++ of the iterator more complicated, i've done it and it works, but i have this new problem that i wrote before, you said that it's because i don't have to increment *ptr but ptr, but if i dont increment *ptr i'm not able to pass from one row to another skipping values between rows...
As you said my iterator needs to contain a simple pointer to the element, and it would fix my last problem, but with a simple pointer to the element it would not be able to skip values between rows, cause my data are not contiguos...
Feb 8 '10 #9
weaknessforcats
9,208 Expert Mod 8TB
This is your matrix class method:

Expand|Select|Wrap|Line Numbers
  1. matrice(sizet rw, sizet cl) { //causa errore in valgrind 
  2.     _data=new valuet*[rw]; 
  3.     for(sizet i=0;i<rw;i++) 
  4.       _data[i]=new valuet[cl]; 
  5.     _row=rw; 
  6.     _col=cl; 
  7.   } 
Look at your allocations:
1) first an array oif pointers,
2) then an array of elements for each pointer.

This is identical to

_
Expand|Select|Wrap|Line Numbers
  1. data = new valuet[rw][cl];
except that now your array is contiguous. Remember, to call it an array, the elements must be contiguous.

But even if you keep your original scheme, the iterator should know the structure and perform whatever calculations are necessary to acquire the address of a single pointer. A non-contiguous array can't use pointer arithmetic, but it is doable. Personally. I would allocate an [rw][cl] array provided I know the dimensions at the outset and they will not change during the life of the program.

In any case, I say for the third time: You need the address of a single element to be returned from your array and not the address of something else. Otherwise, it's not an iterator.

I say that because you should be able to create iterators that each point to different array elements allowing you to iterate over that range.
Feb 8 '10 #10
thanks again for your patience, now i'm trying to do it like you suggested...
i've declared data like a pointer to my value type (valuet *data), then in constructor when i do:
data = new valuet[row][col];
i get this error:
error: 'col' cannot appear in a constant-expression

it doesn't allow me to create a bidimensional array but just a normal array...
Feb 11 '10 #11
weaknessforcats
9,208 Expert Mod 8TB
That's because there are no multi-dimensional arrays in C or C++. You always have to specify the element size so the compiler can generate the correct allocation code. That means cl must be a const value.

You may need cl to be a const class member and you set a value in cl using the initializer list of your constructors.
Feb 11 '10 #12

Sign in to post your reply or Sign up for a free account.

Similar topics

9
by: Alexander Stippler | last post by:
Hi, I've got trouble with some well known issue. Iterator invalidation. My situation: for (it=v.begin(); it!=v.end(); ++it) { f(*it); } Under some circumstances, f may alter the container...
5
by: Jason | last post by:
Hello. I am trying to learn how operator overloading works so I wrote a simple class to help me practice. I understand the basic opertoar overload like + - / *, but when I try to overload more...
7
by: Ben | last post by:
Hi all, I'm not yet good at thinking the right way in c++ so although I could solve this problem, I'm not sure if they way I'm thinking of is the best way to do it. I need a data type or class...
13
by: Charulatha Kalluri | last post by:
Hi, I'm implementing a Matrix class, as part of a project. This is the interface I've designed: class Matrix( )
9
by: Paul Rubin | last post by:
Is there a good reason to not define iter1+iter2 to be the same as itertools.chain(iter1, iter2)? Examples: # all lines in a collection of files, like perl <> all_lines = file1 + file2 +...
7
by: check.checkta | last post by:
Hi, I'd like to implement a simple matrix class. I'd like to overload operator so that it returns as a vector (either the stl vector or some other Vector class of my own). The reason I want...
3
by: John | last post by:
I have a class of my own which has a 2d matrix of type T. I want to give the users of my library an iterator to iterator thru all the elements of this matrix ( they dont need to know anything about...
1
by: atomik.fungus | last post by:
Hi, I'm re-writting my matrix class to practice my programming and the computer doesn't let me compile the next code: ( this example come from the constructor of the class) //the matrix is made...
6
by: Mark | last post by:
I have a problem with a template class defined: // start matrix.h file template <class Tclass Matrix { public: Matrix() { // default constructor } Matrix(const Subscript rows, const...
2
by: DarrenWeber | last post by:
Below is a module (matrix.py) with a class to implement some basic matrix operations on a 2D list. Some things puzzle me about the best way to do this (please don't refer to scipy, numpy and...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.