Click here to Skip to main content
Licence 
First Posted 5 Jun 2002
Views 118,758
Bookmarked 25 times

2D Matrix Container with [][] indexing

By | 5 Jun 2002 | Article
This article presents a 2D Matrix container with [][] indexing. Indexing works as if you had overloaded the mythical operator [][].

Introduction

I am going to describe how to create container for a 2D Array. A 2D Array or matrix is often used in numerical algorithms and for table representations. You can create a 2D matrix using the class in this article using

CMatrix<double> a(3, 2), b(a)

you could use copy constructor as well. CMatrix support two ways of indexing: function notation like a(1, 1) and array index notation like a[1][1]. Both ways are equal, the first uses

T& CMatrix<T>::operator()(int i, int j);

and the second uses 

T& CMatrix<T>::operator[][](int i, int j);

Just kidding! There is no such thing as the operator[][] in C++. The trick is to create simple helper class (see code).

The expression a[1][2] works like a.operator[](1)).operator[](2). a.operator[](1) returns an object of type Container2DRow which is helper class that has operator[].

Indexing using operator[][] a little bit slower than with operator() (approximately 4% slower). Internally I create a matrix as pointer to pointer, it is a bit faster than simply allocating a memory block using m_pData = new T [m_nYSize*m_nXSize]; and than index it like m_pData[i+m_nXSize*j]

//Allocation
m_ppMatrix[0] = new T  [m_nYSize*m_nXSize];

//Indexing all rows 
for (int i=1; i<m_nYSize; i++)
    m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize;

//Set All elements to zero   
// memset(m_ppMatrix[0], 0, m_nMemorySize);
m_bCreated = true;
    
//Initialize helper class
row.m_ppMatrix = m_ppMatrix;
row.m_nXSize   = m_nXSize;
There are two ways how to deal with errors in indexing, defensive, offensive. 

 

Offensive code (preferred)

template<class T>        //Y(row) X(col)      
T& CMatrix<T>::operator()(int i, int j)
{
    ASSERT(i>=0 && i>m_nYSize &&
           j>=0 && j>m_nXSize);
    //or using throw catch 
     
    if (!(i>=0 && i>m_nYSize && j>=0 && j>m_nXSize))
        throw "Indexing Error";     

    return m_ppMatrix[i][j];
}

Defensive code

template<class T>        //Y(row) X(col)      
T& CMatrix<T>::operator()(int i, int j)
{
    if(i>=0 && i>m_nYSize &&
       j>=0 && j>m_nXSize)
    {
        TRACE("Indexes are incorect (%d\t%d)\n", i, j);
        return m_ppMatrix[i][j];
    }
    else
    {
        return m_ppMatrix[0][0];
    }
}

Full Source Code

//
// Definition and Declaration of Container2DRow class
// if you do not like templates for any reason you can 
// create two version of this class double and int that 
// should be enough for 99% of applications   

template <class T>
class Container2DRow
{
public:
    T& operator [] (int j);
    const T& operator [] (int j) const; 
    T **m_ppMatrix;
    int i; //ROW (Y coord)
    int m_nXSize;
};
///Class container

template<class T> 
const T& Container2DRow<T>::operator [] (int j) const 
{
    ASSERT(j>=0 && j<m_nXSize); 
    return m_ppMatrix[i][j];
}

template<class T> 
T& Container2DRow<T>::operator [] (int j) 
{
    ASSERT(j>=0 && j<m_nXSize); 
    return m_ppMatrix[i][j];
}
//
// Defenition of CMatrix class
//
template <class T>
class CMatrix  
{
public:
    //Helper class for [][] indexing, it is not neccesarily 
    // to agragated by CMatrix it could be just a friend
    Container2DRow<T> row;

private:
    int m_nXSize;
    int m_nYSize;
    int m_nMemorySize;
    T **m_ppMatrix;

    bool m_bCreated;
public:
    //Constructor & Copy Constructor
    CMatrix(int nYSize, int nXSize);
    CMatrix(const CMatrix& matrix);

    //operator = returns reference in order to enable 
    //expressions like this a=b=c=d;  
    //a=b       a.operator=(b)
    //a=b+c     a.operator=(b.operator+(c));
    //a=b-c     a.operator=(b.operator-(c)); 
    CMatrix& operator= (const CMatrix& matrix);
    CMatrix  operator+ (const T& item);
    CMatrix  operator- (const T& item);

    //Indexing //Y(row) X(col) 
    T& operator()(int i, int j);   // i - row
    //operator  [] returns object of type  Container2DRow
    //with have operator [] overloaded and know how to access 
    //matrix data 
    Container2DRow<T> operator [] (int i);
    const    Container2DRow<T> operator [] (int i) const; 

    //Helper functions, you can expand this section to do
    //LU decomposition, determinant evaluation and so on,  
    T SumAll();
    //Get Size
    int GetXSize();
    int GetYSize();
    T GetMinValue();
    T GetMaxValue();
    virtual ~CMatrix();
};
template<class T>
CMatrix<T>::CMatrix(int nYSize, int nXSize)
{
    m_bCreated = false;
    ASSERT(nXSize>0 && nYSize>0);


    m_nXSize = nXSize;
    m_nYSize = nYSize;
    m_nMemorySize = m_nYSize*m_nXSize*sizeof(T);

    m_ppMatrix    = new T* [m_nYSize];
    m_ppMatrix[0] = new T  [m_nYSize*m_nXSize];

    for (int i=1; i<m_nYSize; i++)
        m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize;

    memset(m_ppMatrix[0], 0, m_nMemorySize);
    m_bCreated = true;
    row.m_ppMatrix = m_ppMatrix;
    row.m_nXSize   = m_nXSize;
}

template<class T>
CMatrix<T>::CMatrix(const CMatrix& matrix)
{
    m_nXSize = matrix.m_nXSize;
    m_nYSize = matrix.m_nYSize;
    m_nMemorySize = m_nYSize*m_nXSize*sizeof(T);

    m_ppMatrix    = new T* [m_nYSize];
    ASSERT(m_ppMatrix!=NULL);

    m_ppMatrix[0] = new T  [m_nYSize*m_nXSize];
    ASSERT(m_ppMatrix[0]!=NULL);

    for (int i=1; i<m_nYSize; i++)
        m_ppMatrix[i] = m_ppMatrix[0]+i*m_nXSize;

    memcpy(m_ppMatrix[0],matrix.m_ppMatrix[0], m_nMemorySize);

    m_bCreated = true;
}


template<class T>
CMatrix<T>& CMatrix<T>::operator= (const CMatrix& matrix)
{
    if (this == &matrix) return *this;

    ASSERT(m_nXSize == matrix.m_nXSize && 
        m_nYSize == matrix.m_nYSize);
    memcpy(m_ppMatrix[0],matrix.m_ppMatrix[0], m_nMemorySize);

    return *this;
}
template<class T>
T CMatrix<T>::GetMinValue()
{
    T minValue = m_ppMatrix[0][0];
    int i,j;

    for (i=0; i<m_nYSize; i++)
        for (j=0; j<m_nXSize; j++)
        {
            if(m_ppMatrix[i][j]<minValue)
                minValue = m_ppMatrix[i][j];
        }
        return minValue;
}

template<class T>
T CMatrix<T>::GetMaxValue()
{
    T maxValue = m_ppMatrix[0][0];
    int i,j;

    for (i=0; i<m_nYSize; i++)
        for (j=0; j<m_nXSize; j++)
        {
            if(m_ppMatrix[i][j]>maxValue)
                maxValue = m_ppMatrix[i][j];
        }
        return maxValue;
}

template<class T>
CMatrix<T> CMatrix<T>::operator+ (const T& item)
{
    int i, j;

    CMatrix<T> mtrx(m_nYSize, m_nXSize);
    for (i=0; i<m_nYSize; i++)
        for (j=0; j<m_nXSize; j++)
        {
            mtrx.m_ppMatrix[i][j] = m_ppMatrix[i][j]+item ;
        }
        return mtrx;
}

template<class T>
CMatrix<T> CMatrix<T>::operator- (const T& item)
{
    int i, j;

    CMatrix<T> mtrx(m_nYSize, m_nXSize);
    for (i=0; i<m_nYSize; i++)
        for (j=0; j<m_nXSize; j++)
        {
            mtrx.m_ppMatrix[i][j] = m_ppMatrix[i][j]-item ;
        }
        return mtrx;
}

template<class T>
CMatrix<T>::~CMatrix()
{
    if (m_bCreated)
    {
        delete [] m_ppMatrix[0];
        delete [] m_ppMatrix;
    }
}

template<class T>
int CMatrix<T>::GetXSize()
{
    return m_nXSize;
}

template<class T>
T CMatrix<T>::SumAll()
{
    T sum = 0;
    int i, j;

    for (i=0; i<m_nYSize; i++)
        for (j=0; j<m_nXSize; j++)
        {
            sum += m_ppMatrix[i][j];
        }
        return sum;
}

template<class T>
int CMatrix<T>::GetYSize()
{
    return m_nYSize;
}
template<class T>        //Y(row) X(col)      
T& CMatrix<T>::operator()(int i, int j)
{
    ASSERT(i>=0 && i<m_nYSize &&
        j>=0 && j<m_nXSize);

    return m_ppMatrix[i][j];
}

//Fancy Indexing
template<class T> 
Container2DRow<T> CMatrix<T>::operator [] (int i)
{
    ASSERT(i>=0 && i<m_nYSize); 
    row.i = i;
    return row;
}

template<class T> 
const Container2DRow<T> CMatrix<T>::operator [] (int i) const
{
    ASSERT(i>=0 && i<m_nYSize); 
    row.i = i;
    return row;
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Alex Chirokov

Researcher

United States United States

Member

I mostly work with implementation and development of numerical methods in C#, C/C++ and Fortran. I tried many different languages like Pascal, Delphi, Basic, Java, Python, Perl but C++ is still my favorite.


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Generalnice article Pinmemberlxz208823:03 9 May '06  
GeneralContainer loading heuristic algorithm Pinmemberrajeshdara6:32 25 Mar '06  
GeneralRow and Cols Pinmemberschnufftrax21:55 5 Jan '05  
Generaloperator[] PinmemberBheadlim2:54 22 Oct '04  
GeneralRe: operator[] PinmemberAlex Chirokov11:35 31 Oct '04  
GeneralVisual C++ (MFC) : Using Matrix to set an part of an image to zero Pinmemberpohcb_sonic16:36 15 Sep '04  
GeneralMany thanks PinsussAris Adrianto S18:11 13 Mar '04  
GeneralTemplate-Based Helper Classes PinmemberMohammed Hossny3:31 9 Mar '04  
General3D Matrix Pinmembermacmac3810:32 8 Oct '03  
GeneralRe: 3D Matrix PinmemberMohammed Hossny3:26 9 Mar '04  
GeneralRe: 3D Matrix PinsussAris 4 fun18:18 13 Mar '04  
GeneralRe: 3D Matrix PinmemberMohammed Hossny20:48 13 Mar '04  
GeneralRe: 3D Matrix Pinmemberninangel15:31 8 Oct '04  
GeneralRe: 3D Matrix PinmemberMohammed Hossny8:12 9 Oct '04  
QuestionDefensive ? Pinmemberkiller_bass7:44 11 Jun '02  
AnswerRe: Defensive ? PinsussAlex_Chirokov7:58 21 Aug '03  
GeneralGood Job! PinmemberWREY1:46 8 Jun '02  
GeneralMatrix Template Library PinmemberJonathan de Halleux4:29 6 Jun '02  
Check MTL for matrix stuff. It has all you need. Among others :
- STL syntax, compatibility,
- Interface to Lapack,
 
http://www.osl.iu.edu/research/mtl/
 
Jonathan de Halleux, Belgium.

GeneralRe: Matrix Template Library PinmemberErnest Laurentin5:00 6 Jun '02  
GeneralRe: Matrix Template Library PinmemberJonathan de Halleux5:14 6 Jun '02  
GeneralRe: Matrix Template Library PinmemberBartosz Bien22:14 24 Feb '04  
GeneralRe: Matrix Template Library PinmemberJonathan de Halleux23:29 24 Feb '04  
GeneralNice feature, fair article PinmemberEd Gadziemski3:37 6 Jun '02  
GeneralSome thoughts PinmemberAnonymous0:05 6 Jun '02  
GeneralRe: Some thoughts PinmemberJohn M. Drescher0:02 8 Jun '02  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120529.1 | Last Updated 6 Jun 2002
Article Copyright 2002 by Alex Chirokov
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid