Code Newbie
News     Forums     Search     Members     Sign Up    

My Code Newbie
Username

Password

Articles/Snippets
ASP Classic
ASP.NET
C
C#
C++
HTML / CSS
Java
Javascript
Linux / BSD
Perl
PHP
Python
Ruby
SQL
VB 6
VB.NET

C.N. Friends
  Planet Rome

Link to Us!
Code Newbie
  Code Newbie
    forums

Go Back   Code Forums > Application and Web Development > Standard C, C++

Reply
 
LinkBack Thread Tools Display Modes
Old 01-30-2005, 07:56 PM   #1 (permalink)
abs
Registered User
 
Join Date: Jan 2005
Posts: 7
abs is on a distinguished road
C++ Multi Dimensional Array using Vectors.

Hi, I am trying to create a 2d vector, and have it so I can access it much like an 2d array (ie array[][]).
I stumbled across this implementation and was trying to get it to work (original code)

i changed it a bit...
Code:
#include <vector>
using namespace std;

template <class T>
class C2DVector
{
public:
 template<typename _T> friend ostream& operator << (ostream&, C2DVector<_T>);
   C2DVector():m_dimRow(0), m_dimCol(0){;}
   C2DVector(int nRow, int nCol) {
      m_dimRow = nRow;
      m_dimCol = nCol;
      for (int i=0; i < nRow; i++){
         vector<T> x(nCol);
         int y = x.size();
         m_2DVector.push_back(x);
      }
   }
   void SetAt(int nRow, int nCol, const T& value) {
      if(nRow >= m_dimRow || nCol >= m_dimCol)
       ; // throw out_of_range("Array out of bound");
      else
         m_2DVector[nRow][nCol] = value;
   }
   T GetAt(int nRow, int nCol) {
      if(nRow >= m_dimRow || nCol >= m_dimCol)
	cerr<<"array out of bounds"<<endl;//throw out_of_range("Array out of bound");
      else
         return m_2DVector[nRow][nCol];
   }
   void GrowRow(int newSize) {
      if (newSize <= m_dimRow)
         return;
      m_dimRow = newSize;
      for(int i = 0 ; i < newSize - m_dimCol; i++)   {
         vector<int> x(m_dimRow);
         m_2DVector.push_back(x);
      }
   }
   void GrowCol(int newSize) {
      if(newSize <= m_dimCol)
         return;
      m_dimCol = newSize;
      for (int i=0; i <m_dimRow; i++)
         m_2DVector[i].resize(newSize);
   }
   vector<T>& operator[](int x)    {
      return m_2DVector[x];
   }
private:
   vector< vector <T> > m_2DVector;
   unsigned int m_dimRow;
   unsigned int m_dimCol;
};
template <typename T>
ostream& operator << (ostream& os, C2DVector<T> test)
{
  for (int i=0; i < test.m_dimRow; i++){
     
    for (int j=0; j < test.m_dimCol; j++){
      os << test[i][j] << " ";
     
    }
    os << endl;
      }

    return os;
 
}
so here is how Im trying to use it...
Code:
#include <iostream>
#include <vector>
#include "mvector.cc"

using namespace std;

struct object
{
  //For now, lets test on a 5x5 matrix
  object()
  {
     array = new C2DVector<int>(5,5);
  }

  C2DVector<int> *array;
};

int main()
{
  //Lets try creating it by hand.
  C2DVector<int>a(3,3);

  a[0][0]=1;
  a[0][1]=1;
  a[0][2]=1; 
  a[1][0]=1;   
  a[1][1]=1;
  a[1][2]=2;
  a[2][0]=1;
  a[2][1]=3;
  a[2][2]=4;
cout<<a<<endl;
  // It works correctly. 
 
  object * start;
  start = new object;
  start->array->SetAt(1,1,1);//Works
cout<< *start->array<<endl;
  
*start->array[1][2]=2;//Does not work!
  return 0;
}
I'm not sure whyi can't get the [][] access to work. I would think the overloaded:
vector<T>& operator[](int x) would let me gain access to column's of the 2dvector.
I can't even compile with *start->array[1][2]=2 . I thought this line means, I'm accessing the value of the array, start points to, at [1][2] and assigning it to 2.

Any insight would be helpful. thanks!
abs is offline   Reply With Quote
Old 01-31-2005, 05:50 AM   #2 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
I'll take a peek at it in a few hours if no one beat me to it.
__________________
Valmont is offline   Reply With Quote
Old 01-31-2005, 02:07 PM   #3 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
Why not making your life easier?
Code:
#ifndef C2DMATRIX_H
#define C2DMATRIX_H

#include <vector>
#include <string>
#include <iostream>
#include <stdexcept>

using namespace std;

class C2DMatrixError
{
public:
  C2DMatrixError(std::string msg) : sMsg_(msg)
    {}
  virtual std::string what() = 0;
protected:
  std::string sMsg_;
};

//--

class BadSize : public C2DMatrixError
{
public:
  BadSize(std::string msg) : C2DMatrixError(msg)
    {}
  std::string what()
  {
    return sMsg_;
  } 
};

//--

class BoundsViolation : public C2DMatrixError
{
public:
  BoundsViolation(std::string msg) : C2DMatrixError(msg)
    {}
  std::string what()
  {    
    return sMsg_;
  }
};

//--

template<typename T>
class C2DMatrix 
{
public:
  C2DMatrix() {}
  C2DMatrix(unsigned, unsigned );
  
  T& operator() (unsigned, unsigned);
  const T& operator() (unsigned i, unsigned j) const;   
   size_t nRows_;
   size_t nCols_;
private:
  vector<vector<T> > data_;
  template <typename _T>
  friend ostream& operator<<(ostream&  os, C2DMatrix<_T>& c2d );
};

//---------------------------
 
template<typename T>
C2DMatrix<T>::C2DMatrix(unsigned rows, unsigned cols)  
{
  if (rows == 0 || cols == 0)
  {
    throw BadSize("ERROR: Bad size");
  }
  data_.resize(rows);
  nRows_=rows;
  nCols_=cols;
  for (unsigned i = 0; i < rows; ++i)
  {
    data_[i].resize(cols);
  }
}
 
//----------------------------

template<typename T>
inline T& C2DMatrix<T>::operator() (unsigned row, unsigned col)
{
  if (row >= nRows_ || col >= nCols_ ) 
  {
    throw BoundsViolation("ERROR in non-const operator(): Bounds Violation");
  }
  return data_[row][col];
} 
 
//----------------------------

template<typename T>
inline const T& C2DMatrix<T>::operator() (unsigned row, unsigned col) const
{
  if (row >= nRows_ || col >= nCols_)
  {
    throw BoundsViolation("ERROR in const operator()const: Bounds Violation");
  }
  return data_[row][col];
}
 
//-----------------------------

template <typename T>
ostream& operator<< (ostream&  os, C2DMatrix<T>& c2d)
{
  for (int i=0; i < c2d.nRows_; i++)
  {
    for (int j=0; j < c2d.nCols_; j++)
    {
      os << c2d(i,j) << " ";
    }
    os << endl;
  }
  return os; 
}

#endif //C2DMATRIX_H
Code:
#include "C2DArray.h"
#include <iostream>
#include <cstdlib>
#include <vector>

using namespace std;

class object 
{
public:
  object() : array(C2DMatrix<int>(1,1))
  { }
  C2DMatrix<int> array;
};

int main()
{
  try
  {
    object start;
    cout<<start.array<<endl;  
    start.array(1,1)=1;
    cout<<start.array<<endl;
  }
  catch(C2DMatrixError& err)
  {
    cout<<err.what()<<endl;
  }
    
  return 0;
}
__________________
Valmont is offline   Reply With Quote
Old 01-31-2005, 02:10 PM   #4 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
*edit*
__________________
Valmont is offline   Reply With Quote
Old 01-31-2005, 04:04 PM   #5 (permalink)
abs
Registered User
 
Join Date: Jan 2005
Posts: 7
abs is on a distinguished road
Cool! The code is much cleaner. I just need to brush up on exeception handling, but I think can probably write my own implementation in the future now. A few questions though...

1)
IF I were to ever try to do what I was doing in my original post ( access that array via [ ] [ ]). How would I do it? Even though i wouldn't use that implementation anymore, it bugs me that I can't get the syntax for it to work. What's wrong with *start->array[1][2]=2; ?

2) What naming convetion are you using for your code? I figure it's a good time to start organizing my code a bit.

Thanks!
abs is offline   Reply With Quote
Old 01-31-2005, 04:11 PM   #6 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
Quote:
I just need to brush up on exeception handling
The class C2DMatrixErroris a base class for specialized errors.
All I need to do is throw derrived classes from it as it fits my needs.
All I need to do is catch a C2DMatrixError& class. I've provided every class with an own what() member, derrived from the base class virtual what() member. so the base class object will always return the right version of what().

Caveat:
Obseverve the ampersand (&) in C2DMatrixError& closely (see main() function). Otherwise we won't enjoy polymorphism.
Tips:
- All what() versions for the derrived classes are the same, so you could have defined it in the base class only. However, you can specialize your what() members.
- This is better (add const): catch(const C2DMatrixError& err) {//...}
- This is better: void what() const;
- Observe how I overloaded operator()(). That is a new style. Doesn't mean I endorse it with all my heart.
- Observe how I overloaded TWO versions of operator()(). It is always a good idea that these overloads come in pairs: a const and a non-const version. Otherwise you won't be able to pass const types. Same goes when overloading operator[]() obvoiusly since this is the mother of our idea we have in this excercise.
- Remove the "cerr<<" from the class. A container shouldn't be responsible for output to anything. A container should contain

Quote:
IF I were to ever try to do what I was doing in my original post ( access that array via [ ] [ ]). How would I do it? Even though i wouldn't use that implementation anymore, it bugs me that I can't get the syntax for it to work. What's wrong with *start->array[1][2]=2; ?
From your original posted code, this works. See what happens.
Code:
object* obj = new object;
  (*obj->array)[0][0]=12;
  (*obj->array)[1][1]=24;
  
  cout<<(*obj->array)[0][0]<<endl;
  cout<<(*obj->array)[0][0]<<endl;
  
  cout<<(*obj->array)<<endl;
Try it without encapsulation first to see it more clearly:
Code:
C2DVector<int> *array = new C2DVector<int>(5,5);
  (*array)[0][0]=234;
  cout<<(*array)[1][1]<<endl;
1b) Creating a STL container on the heap (using new) is hard to handle. Don't do that. Unless you need thousands of them.

2a) members: name_
2a2) std::string members: sName_
2a3) members as counter: nName_
2b) functions: some_function()
2c) classes: UppercaseName


Nothing fancy.
__________________

Last edited by Valmont; 01-31-2005 at 05:45 PM.
Valmont is offline   Reply With Quote
Old 02-01-2005, 12:48 AM   #7 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
Oops, in my original code change to this (I initialized the matrix wrong):
Code:
class object 
{
public:
  object() : array(2,2) //  this has been changed now.
  { }  
  C2DMatrix<int> array;
};
__________________
Valmont is offline   Reply With Quote
Old 02-01-2005, 06:32 AM   #8 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
And you'd like to see perhaps some output optimization for HUGE matrices. This technique comes in handy for N x N matrices where hundreds of thousands, millions and more elements could be created:
Code:
template <typename T>
class print_vector
{
public:
   void operator()(const std::vector<T>& v)
   {
      std::copy(v.begin(), v.end(), std::ostream_iterator<T>(std::cout, " "));
      std::cout<< " " << std::endl;
   }
};

//-------------------------------

template <typename T>
ostream& operator<< (std::ostream&  os, C2DMatrix<T>& c2d)
{
  typename std::vector<std::vector<T> >::iterator it_end = c2d.get_internal_rep().end();  
  typename std::vector<std::vector<T> >::iterator it_begin = c2d.get_internal_rep().begin();
  
  std::for_each( it_begin, it_end, print_vector<T>() );
  
  return os; 
}
Don't forget to make an accessor:
Code:
template <typename T>
C2DMatrix<T>::vector<vector<T> >& get_internal_rep()
{
   return data_;
}
__________________
Valmont is offline   Reply With Quote
Old 02-01-2005, 01:16 PM   #9 (permalink)
abs
Registered User
 
Join Date: Jan 2005
Posts: 7
abs is on a distinguished road

im not sure i understand how that is optimized...
the << operator you are still going through the vector and printing out each element. but i'm guessing that copying the elements directly to ostream cout is faster?
abs is offline   Reply With Quote
Old 02-01-2005, 03:01 PM   #10 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
Bulk operations will benefit from the stream iterators greatly. As it happens to be they behave like a container, so we can use them quite elgantly. They are fast for mass storage/retreival.

Tip:
- Don't forget to overload your extraction/insertion operators. It is crucial as you will obviously see.
- Learn to include the <iterator> header. The standard requires it, yet a only a relative few include them. The fact code often works without the include is bad luck: compiler designers mistake.
- Check out: istreambuf_iterator<> as well.
- Check out: back_insert_iterator<>() as well.

Code:
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <iterator>
#include <algorithm>

// istream_iterator, ostream_iterator bulk operations demo.
// 1) We create a file of martian data, by stream a vector towards ostream.
// 2) Then we empty the vector.
// 3) We load the file back into the vector and view its contents.

using namespace std;

//--

struct Martian
{
   int age_;
   bool gender_;
   string species_;
};

//--

ostream& operator<<(ostream& os, const Martian& md)
{
   os<<md.age_<<" "<<md.gender_<<" "<<md.species_;
   return os;
}

//--------------------------------------------------

istream& operator>>(istream& is, Martian& md)
{
  is>>md.age_>>md.gender_;
  //So the species (std::string) name can have spaces.
  getline(is, md.species_);
  return is;
}

//--------------------------------------------------

void save_db(vector<Martian>& mguide)
{
  ofstream outfile("MartianData.txt");
  copy(mguide.begin(), mguide.end(), ostream_iterator<Martian>(outfile, "\n") );
  outfile.close();
}

//--------------------------------------------------

void open_db(vector<Martian>& mguide)
{
  ifstream infile("MartianData.txt");
  copy( istream_iterator<Martian>(infile), istream_iterator<Martian>(),
    back_inserter(mguide) );
  infile.close();
}

//--------------------------------------------------


int main(int argc, char *argv[])
{

  Martian theMd;
  vector<Martian> martianGuide;
  //Let's create some martian info and dump it in a vector.
  theMd.age_ = 320;
  theMd.gender_ = false;
  theMd.species_ = "Crater Planktons";
  martianGuide.push_back(theMd);
  
  theMd.age_ = 243;
  theMd.gender_ = false;
  theMd.species_ = "Mountain Worms";
  martianGuide.push_back(theMd);
  
  theMd.age_ = 211;
  theMd.gender_ = true;
  theMd.species_ = "Sky Fish";
  martianGuide.push_back(theMd);
  
  //Let's save it to a file.
  save_db(martianGuide);
  //Emtpy this vector.
  martianGuide.erase(martianGuide.begin(), martianGuide.end() );
  //Fill the vector again to verify correct storage and operator>> overload.
  open_db(martianGuide);
  
  copy(martianGuide.begin(), martianGuide.end(), ostream_iterator<Martian>(cout, "\n"));

  return 0;
}
__________________
Valmont is offline   Reply With Quote
Old 02-02-2005, 06:22 PM   #11 (permalink)
abs
Registered User
 
Join Date: Jan 2005
Posts: 7
abs is on a distinguished road
the more i learn, the more questions i have...

^Looks interesting.. I'll have to look over it more when I have time this weekend.

Another question...
Is there something special with templates? By special, I mean some sort of conversion... because when I took the C2DMatrix class you wrote, and changed it from a template to type 'int', I can no longer execute:

Code:
object start; //so start.array is hardcoded to be of type 'int'
start.array(1,1) = 1;
I get a "error: non-lvalue in assignment" error.
abs is offline   Reply With Quote
Old 02-02-2005, 11:11 PM   #12 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
Originally your code created an instance of struct "object".
(Don't name your structs, classes, and types with only lower case letters next time).
Code:
object * start;
  start = new object;
And your struct set us up a matrix of ints.
Code:
struct object
{
  //For now, lets test on a 5x5 matrix
  object()
  {
     array = new C2DVector<int>(5,5);
  }

  C2DVector<int> *array;
};
That means: that is the intention, looking at the declaration of C2DVector<int>*.
But this code is faulty anyway (although compilers accept it!).
So I've adapted it:
Code:
class object 
{
public:
  object() : array(2,2) //  this has been changed now.
  { }  
  C2DMatrix<int> array;
};
So I haven't changed anything. If I did, then your struct is ambigious.

All in all, this stuct of int-matrices work perfectly:
Code:
class object 
{
public:
  object() : array(2,2)
  { }  
  C2DMatrix<int> array;
};


int main()
{  
  try
  {
    object start;
    
    start.array(0,0)=1;
    start.array(1,1)=2;
    cout<<start.array<<endl;
  }
  catch(C2DMatrixError& err)
  {
    cout<<err.what()<<endl;
  }
    
  return 0;
}
__________________
Valmont is offline   Reply With Quote
Old 02-02-2005, 11:41 PM   #13 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
Wait a minute...
How did you change the matrix class? Post it please.
__________________
Valmont is offline   Reply With Quote
Old 02-03-2005, 12:00 AM   #14 (permalink)
abs
Registered User
 
Join Date: Jan 2005
Posts: 7
abs is on a distinguished road
i think you misunderstood my question...

i took the template...
Code:
template<typename T>
class C2DMatrix 
{
 public:
  C2DMatrix() {}
  C2DMatrix(unsigned, unsigned );
  T& operator() (unsigned, unsigned);
  const T& operator() (unsigned i, unsigned j) const;   
  size_t nRows_;
  size_t nCols_;
  vector<vector<T> > data_;
 private:
  template <typename _T>
    friend ostream& operator<<(ostream&  os, C2DMatrix<_T>& c2d );
};
and changed the class to 'int' type..

Code:
class C2DMatrix 
{
 public:
  C2DMatrix() {}
  C2DMatrix(unsigned, unsigned );
  
  int operator() (unsigned, unsigned);
  const int operator() (unsigned i, unsigned j) const;   
  size_t nRows_;
  size_t nCols_;
  vector<vector<int> > data_;
 private:
    friend ostream& operator<<(ostream&  os, C2DMatrix& c2d );
};
now assignment (ex: array(int,int) = int ) gives me that lvalue error.
So I was asking if there were anything different about how template classes are interpreted or referenced, compared to a non-template class. My understanding of templates is that the template type is bound at compile time, so I don't see why C2DMatrix<int> array, would be any different from C2DMatrix array (if C2DMatrix was hardcoded to type 'int'). ;p
abs is offline   Reply With Quote
Old 02-03-2005, 07:04 AM   #15 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
I assume you changed the implementation of the class as well. Not only its declaration.
Next step is to change it correctly. You didn't. Observe the details.

There is no difference between changing it to int or keeping it a template. Not even in speed!
__________________
Valmont is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


Similar Threads
Thread Thread Starter Forum Replies Last Post
Different string types in C: char pointer, char array, etc. Sleep Standard C, C++ 0 01-23-2005 08:40 PM
working with Multi Dimensional Arrays sde PHP 7 07-11-2004 01:43 PM
sorting multi dimensional arrays sde PHP 4 10-01-2003 05:52 PM
edit? anon Lounge 10 11-21-2002 03:02 PM


All times are GMT -8. The time now is 12:48 AM.


Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.0.0 RC8





Copyright © 2000-2008, Milano Interactive
Web Hosting provided by Portal 360 Web Hosting