Custom Re-sizable Multidimensional Array Container Class

  • (2 Pages)
  • +
  • 1
  • 2

19 Replies - 1874 Views - Last Post: 14 March 2011 - 02:08 PM Rate Topic: -----

#1 novacrazy  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 117
  • Joined: 01-March 11

Custom Re-sizable Multidimensional Array Container Class

Posted 13 March 2011 - 09:40 PM

I've been working on this for a while, and it works almost perfectly. Obviously I'm still making it better and will be adding new functionality. Hence the name "Matrix", I intend to create functions and such to perform matrix operations with this. Anyways, enjoy! ^_^
#include <math.h>
#include <complex>
#include <sstream>
#include <iostream>
#include <string>
#include <exception>
#define array_length(array) (sizeof(array)/sizeof(array[0]))
#define min(x, y) ((x<=y)?x:y)
#define max(x, y) ((x>=y)?x:y)
#define ERROR -1
#define ATTEMPT 3
//class to simply keep track of current matrices and such
class ___s {public: int ___x; ___s(int x){___x = x;};} ___s(0);
//actual class template
template <class math_class = long double>
class matrix
{
protected:
    //matrix dimensions
    int ROW_, COLUMN_;
    //whether or not the matrix has been set to desired size
    bool matrix_set;
    //actual multidimensional array used to store the matrix
    math_class **MATRIX_STO;
public:
    int matrix_number; //simple ID number
    matrix() : ROW_(0), COLUMN_(0), matrix_set(false)
    {
        //basic declaration renders sizeless matrix
        MATRIX_STO = new math_class*[0];
        MATRIX_STO[0] = new math_class[0];
        matrix_number = ___s.___x++;
    }
    matrix(int nRows, int nColumns, bool try_again = true)
    {
        using namespace std;
        try
        {
            MATRIX_STO = new math_class*[nRows];
            for (int x = 0; x < nRows; x++)
            {
                MATRIX_STO[x] = new math_class[nColumns];
            }
            ROW_ = nRows; COLUMN_ = nColumns;
            matrix_set = true;
            matrix_number = ___s.___x++;
        }
        catch (bad_alloc&)
        {
            if (try_again == true)
            {
                _try_set(nRows, nColumns, 3, true, false);
            }
            matrix_set = false;
        }
    }
    void _try_set(int nRows, int nColumns, int try_number = 1, bool display_error = true, bool for_operator = false)
    {
        if (matrix_set == false)
        {
            using namespace std;
            try
            {
                MATRIX_STO = new math_class*[nRows];
                for (int x = 0; x < nRows; x++)
                {
                    MATRIX_STO[x] = new math_class[nColumns];
                }
                ROW_ = nRows; COLUMN_ = nColumns;
                matrix_set = true; cannot_create = false;
                matrix_number = ___s.___x++;
            }
            catch (bad_alloc&)
            {
                for (int current_try = 0; current_try < try_number; current_try++)  {_try_set(nRows, nColumns, 0, false);}
                if (display_error)
                {
                    if (!for_operator)
                    {
                        cerr << "Could not allocate enough memory to create matrix of desired size:\n" << nRows << " by " << nColumns << ". "<< \
                        try_number << ((try_number > 1) ? " attempts were made." : " attempt was made.") << endl;
                    }
                    if (for_operator)
                    {
                        cerr << "Could not allocate requested amount of memory to perform this operation" << ". "<< \
                        try_number << ((try_number > 1) ? " attempts were made." : " attempt was made.") << endl;
                    }
                }; matrix_set = false; cannot_create = true;
            }
        }
    }
    void set_row(int row, math_class a_row[], int number_of_elements)
    {
        using namespace std;
        if (matrix_set)
        {
            if ((row >= ROW_) || ((number_of_elements - 1) >= COLUMN_))
            {
                bool exist = true;
                string __error__ = "";
                if ((row >= ROW_))
                {
                    __error__.append("Row does not exist.\n"); exist = false;

                }
                if ((number_of_elements - 1) >= COLUMN_)
                {
                    if (exist) {__error__.append("Input row is too large and will be truncated.\n");}
                }
                cerr << __error__;
            }
            else
            {
                for (int current_element=0; current_element < number_of_elements; current_element++)
                {
                    MATRIX_STO[row][current_element] = a_row[current_element];
                }
            }
        }
        else {std::cerr << "Matrix not set\n";}
    }
    void set_column(int column, math_class a_column[], int number_of_elements)
    {
        using namespace std;
        if (matrix_set)
        {
            if ((column >= COLUMN_) || ((number_of_elements - 1) >= ROW_))
            {
                bool exist = true;
                string __error__ = "";
                if ((column >= COLUMN_))
                {
                    __error__.append("Column does not exist.\n"); exist = false;

                }
                if ((number_of_elements - 1) >= ROW_)
                {
                    if (exist) {__error__.append("Input row is too large and will be truncated.\n");}
                }
                cerr << __error__;
            }
            else
            {
                for (int current_element=0; current_element < number_of_elements; current_element++)
                {
                    MATRIX_STO[column][current_element] = a_column[current_element];
                }
            }
        }
        else {std::cerr << "Matrix not set\n";}
    }
    math_class get_location(int nRow, int nColumn)
    {
        try
        {
            if ((nRow > ROW_) || (nColumn > COLUMN_))
            {
                throw "Location does not exist ";
            }
            if (matrix_set)
            {
                return MATRIX_STO[nRow][nColumn];
            }
            else throw "Matrix not set ";
        }
        catch (const char* caught)  {std::cerr << caught; return ERROR;}
    }
    void delete_matrix(bool recreate = false, bool show_message = false)
    {
        for(int x = 0; x < ROW_; x++)
        {
            delete[] MATRIX_STO[x];
        }
        delete[] MATRIX_STO;
        matrix_set = false;
        if (show_message) {std::cout << "Deletion succesful\n";}
        if (recreate)
        {
            std::cout << "Recreating Matrix\n";
            _try_set(ROW_, COLUMN_, ATTEMPT, true, true);
            for (int CR = 0; CR < ROW_; CR++)    {for (int CC = 0; CC < COLUMN_; CC++) {MATRIX_STO[CR][CC] = 0;};}
        }
    }
    //resize... well, F*cking hard to design with error handling, thats all I have to say :P/> I did write this myself though, barely any online help.
    void resize(int nRows, int nColumns)
    {
        ___temp_set(nRows, nColumns, 3, true);
        for (int x = 0; x < min(ROW_, nRows); x++)
        {
            for (int y = 0; y < min(COLUMN_, nColumns); y++)
            {
                TEMP_MATRIX[x][y] = MATRIX_STO[x][y];
            }
        }
        if (can_resize)
        {
            delete_matrix();
            _try_set(nRows, nColumns, ATTEMPT, false);
            if (!cannot_create)
            {
                for (int x = 0; x < nRows; x++)
                {
                    for (int y = 0; y < nColumns; y++)
                    {
                        MATRIX_STO[x][y] = TEMP_MATRIX[x][y];
                    }
                }
                std::cout << "Resize to " << nRows << " by " << nColumns << " succesful\n";
            }
            if (cannot_create)
            {
                _try_set(ROW_, COLUMN_, ATTEMPT, false);
                for (int x = 0; x < ROW_; x++)
                {
                    for (int y = 0; y < COLUMN_; y++)
                    {
                        MATRIX_STO[x][y] = TEMP_MATRIX[x][y];
                    }
                }
                std::cerr << "Could not resize after " << ATTEMPT << ((ATTEMPT>1)?" attempts were made. ":" attempt was made. ") << "Data has been recreated unchanged.\n";
            }
        }
        for(int x = 0; x < nRows; x++)
        {
            delete[] TEMP_MATRIX[x];
        }
        delete[] TEMP_MATRIX;
    }
    //simple destructor to avoid memory leaks.
    ~matrix()
    {
        for(int x = 0; x < ROW_; x++)
        {
            delete[] MATRIX_STO[x];
        }
        delete[] MATRIX_STO;
        ___s.___x--;
    }
    private:
        bool can_resize, cannot_create; //used in the resize function
        math_class **TEMP_MATRIX; //temporary matrix used in the resize function
        //to create the TEMP_MATRIX, used in the resize function
        void ___temp_set(int nRows, int nColumns, int try_number = ATTEMPT, bool display_error = true)
        {
            using namespace std;
            try
            {
                TEMP_MATRIX = new math_class*[nRows];
                for (int x = 0; x < nRows; x++)     {TEMP_MATRIX[x] = new math_class[nColumns];}
                can_resize = true;
            }
            catch (bad_alloc&)
            {
                for (int current_try = 0; current_try < try_number; current_try++)  {___temp_set(nRows, nColumns, 0, false);}
                if (display_error)
                {
                    cerr << "Could not allocate requested amount of memory to perform this operation" << ".\n"<< \
                    try_number << ((try_number > 1) ? " attempts were made." : " attempt was made.") << endl;
                }
                can_resize = false;
            }
        }
};


Btw, if you find an error, or would simply like to help me improve this, tell me please. And, of course feel free to use this yourself.

This post has been edited by novacrazy: 13 March 2011 - 09:45 PM


Is This A Good Question/Topic? 1
  • +

Replies To: Custom Re-sizable Multidimensional Array Container Class

#2 janotte  Icon User is offline

  • code > sword
  • member icon

Reputation: 990
  • View blog
  • Posts: 5,141
  • Joined: 28-September 06

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 13 March 2011 - 10:06 PM

I think you might have intended to post this in the snippets section of DIC.
http://www.dreaminco...rowse.php?cid=2
Was This Post Helpful? 0
  • +
  • -

#3 novacrazy  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 117
  • Joined: 01-March 11

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 13 March 2011 - 10:12 PM

View Postjanotte, on 13 March 2011 - 11:06 PM, said:

I think you might have intended to post this in the snippets section of DIC.
http://www.dreaminco...rowse.php?cid=2

It probable could go there, but I was hoping to get some tips on how to make some things better or simply opinions and suggestions on it.
Was This Post Helpful? 0
  • +
  • -

#4 janotte  Icon User is offline

  • code > sword
  • member icon

Reputation: 990
  • View blog
  • Posts: 5,141
  • Joined: 28-September 06

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 13 March 2011 - 11:19 PM

My first comment is what you posted doesn't compile.
Was This Post Helpful? 0
  • +
  • -

#5 novacrazy  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 117
  • Joined: 01-March 11

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 03:46 AM

Well, what does your compiler say about it? So I can try to find the problem.

I created a new project and copied it directly into it and it compiled with no errors or warnings, so I am not sure what is wrong when it compilers on your system. Granted, what I posted doesn't include the main function, but I was expecting people to do that themselves...

This post has been edited by novacrazy: 14 March 2011 - 03:53 AM

Was This Post Helpful? 0
  • +
  • -

#6 janotte  Icon User is offline

  • code > sword
  • member icon

Reputation: 990
  • View blog
  • Posts: 5,141
  • Joined: 28-September 06

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 03:54 AM

Fair enough. Here you go.
Undefined symbols for architecture x86_64:
  "_main", referenced from:
      start in crt1.10.6.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status


Was This Post Helpful? 0
  • +
  • -

#7 novacrazy  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 117
  • Joined: 01-March 11

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 04:20 AM

Just in case anyone needs an example of use, here is an example of the main function to use:

int main()
{
    std::cout << "Hello, world!\n";
    //with the code posted above in the same file or in a header you have included
    matrix<int> *test = new matrix<int>(10, 10); //creates simple ten by ten multidimensional array
    int test_row[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int test_column[] = {1, 3, 5, 7, 9, 11, 13, 15, 17};
    //to set row one. And on larger matrices, the data may not reach the end of the matrix.
    //Also, if the inserted array is larger than the matrix,
    //it will print an error and say the data will be truncated to the matrix size
    test->set_row(1, test_row, array_length(test_row));
    test->set_column(1, test_column, array_length(test_column));
    std::cout << test->get_location(1, 5) << std::endl; //should print 11 at this point
    test->resize(20, 20); //will resize the matrix to 20 by 20, and keeping data.
    //On extremely larger matrices this may not work and errors will be shown, and data may be kept.
    std::cout << test->get_location(1, 5) << std::endl; //to prove data is still there.
    /*NOTES: resizing to a lower size will obviously cause data loss,
    and there are possibilties of the resize not having enough resources to perform the operation.
    I have tried to add in ways of preventing segfaults and such, but they may not be perfect,
    so please alert me on something wrong. Anyways, Enjoy!*/
    delete test;
}


Was This Post Helpful? 0
  • +
  • -

#8 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 09:11 AM

View Postjanotte, on 14 March 2011 - 06:54 AM, said:

Fair enough. Here you go.
Undefined symbols for architecture x86_64:
  "_main", referenced from:
      start in crt1.10.6.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status



To be fair that is NOT a compiler error. That is a linker error. The code seems to compile just fine.
Was This Post Helpful? 0
  • +
  • -

#9 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 09:18 AM

One thing I see is is your use of underscores:

from the standard:

Quote

17.4.3.2.1 Global names [lib.global.names]

Certain sets of names and function signatures are always reserved to the implementation:

Each name that contains a double underscore (_ _) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use.
Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.


lets be honest. You are just making things less readable anyway, if you want to obfuscate your code by making it symbol-rich and variable name ambiguous then why post it and let people see?

When you write code try to think about clarity and maintainability. Just because STL (or other vendor libraries) are all fancy with obscure variable naming conventions and cryptic dense lines of symbols does not mean that you have to follow suit.
Was This Post Helpful? 0
  • +
  • -

#10 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 09:28 AM

Next -- Macros -- The problem with making macros "min()" and "max()" are that they are BOUND to interfere with the user's code! Think about it, there are STL algorithems min and max, but they will get substituted for your min and max and cause errors.

#1 Macros should (as a matter of convention) be in all upper case. MAX and MIN would be slightly better. (also note that COLUMN_, ROW_, MATRIX_STO look like macros because the of the convention - you really should not name non-macro/non-constants in all upper case).

#2 if you are making a library header that you want others to use then you should probably prefix them with some library identifier to make it really unlikely that some yahoo might name a some other symbol with the same name:

MAT_MAX_OF/MAT_MIN_OF might be ok... except someone might think that these macros find the min and max of two matrices.
Was This Post Helpful? 0
  • +
  • -

#11 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 09:35 AM

Next, rather than the rather odd global variable (which you would really want to make into a singelton if you wanted to go this route) why not just add a private static variable to the matrix class.

BTW that is another point -- another convention (not quite as widely followed as macros in all upper case) is that data types are names with the first char upper case. Now there are LOTS of examples where this is not followed and so it is barely a "convention" but it really does help visually separate variables from datatypes... So maybe naming your class Matrix might help.


and that brings me on to an upgrade: Have you considered putting your classes into a namespace? Namespaces are wonderful things for libraries!
Was This Post Helpful? 0
  • +
  • -

#12 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 09:49 AM

Next (ah being a critic is so much FUN! - please take everything I say as trying to help and not just being a nit-picky a-hole).

You put "using namespace std" inside of function (GOOD! so that it does not force this upon the user) -- but you really don't use many std:: functions/objects and you seem to prefix most of them with std:: -- it would probably be better to ditch one or the other (probably better the namespace)).

I can mildly understand cerr inside a Matrix class to deal with errors but WHY FOR THE LOVE OF ALL THAT IS OOP is there cout lines? -- Does a Matrix say anything? Did your Matrix every start talking to you? Does a re-sizeable array every really publish in the American Journal of Dynamic DataTypes? No. SO WHY WOULD I EVER WANT A NOISY MATRIX CLASS!!!

I the programmer decides what the *&^% gets printed, not some library function. Don't put output statements in your data classes, they don't belong there, they are not needed, they will only make your users hate you. :)

. o O(ok I went a litter overboard on that one -- but you did ask for opinions)

<edit> to be fair -- the cout lines all seems to be wrapped in if (show_message) { } blocks with 1 or 2 exceptions.</edit>

Oh and #include<cmath> not #include <math.h>
Was This Post Helpful? 0
  • +
  • -

#13 novacrazy  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 117
  • Joined: 01-March 11

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 10:12 AM

View PostNickDMax, on 14 March 2011 - 10:35 AM, said:

Next, rather than the rather odd global variable (which you would really want to make into a singelton if you wanted to go this route) why not just add a private static variable to the matrix class.

BTW that is another point -- another convention (not quite as widely followed as macros in all upper case) is that data types are names with the first char upper case. Now there are LOTS of examples where this is not followed and so it is barely a "convention" but it really does help visually separate variables from datatypes... So maybe naming your class Matrix might help.


and that brings me on to an upgrade: Have you considered putting your classes into a namespace? Namespaces are wonderful things for libraries!

Originally I did have this within two layered namespaces of math::algebra::matrix, so nothing interferred, and to organize a huge math header I have made. I posted this without those to maintain ease of use, and anyone can do that themselves. I suppose I could make an error log, but then, without looking at the log, the user wouldn't know there had been a bad_alloc or resize problem. Also, I use the underscores as spaces sometimes, makes it more readable in my opinion.

Ummm.. I'll address the other issues when I get home, I'm at school right now. Thank you though.
Was This Post Helpful? 0
  • +
  • -

#14 NickDMax  Icon User is offline

  • Can grep dead trees!
  • member icon

Reputation: 2250
  • View blog
  • Posts: 9,245
  • Joined: 18-February 07

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 10:28 AM

View Postnovacrazy, on 14 March 2011 - 01:12 PM, said:

Originally I did have this within two layered namespaces of math::algebra::matrix, so nothing interferred, and to organize a huge math header I have made. I posted this without those to maintain ease of use, and anyone can do that themselves. I suppose I could make an error log, but then, without looking at the log, the user wouldn't know there had been a bad_alloc or resize problem. Also, I use the underscores as spaces sometimes, makes it more readable in my opinion.

Ummm.. I'll address the other issues when I get home, I'm at school right now. Thank you though.


Well the namespace is just a suggestion I think it may be a little heavy handed for a single class but if you are writing a class for others to consume it can help.

As for the log, I don't really have a problem with the cerr statements although to be honest I would really just prefer that a library throw exceptions with messages -- again, let the programmer decide what the user sees and where error information goes. Its much more use to the programmer and FAR less user to the user -- the user is the one who gets all of these std::cerr messages.

using underscores as spaces is just fine. The standard asks that you do not prefix symbols with underscores:

int _I_am_bad;
int __I_am_worse;
int ___I_am_just_getting_strange;
int I_am_fine;


The only real "buggy" thing I found was the macro names: min/max since those are bound to cause problems with min/max
Was This Post Helpful? 1
  • +
  • -

#15 baavgai  Icon User is online

  • Dreaming Coder
  • member icon

Reputation: 5932
  • View blog
  • Posts: 12,855
  • Joined: 16-October 07

Re: Custom Re-sizable Multidimensional Array Container Class

Posted 14 March 2011 - 10:39 AM

What is this mess?
class ___s {public: int ___x; ___s(int x){___x = x;};} ___s(0);



That's a long way to go to obfuscate the fact you're just allocating a global integer with a number so fugly that you hope no one will use it again.

I'd give a static private to the class.

void _try_set(int nRows, int nColumns, int try_number = 1, bool display_error = true, bool for_operator = false);



??? Why would I ever use this class? It looks like it would simply torture me for the joy of it. Do I really need to resize in place? How do I know how may rows and columns it currently has? Why all the resizing, can't you just make another one?

I'd start out with something like:
template <class math_class = long double>
class matrix {
private:
	static int next_matrix_number;
	int matrix_number; //simple ID number
	int ROWS, COLUMNS;
	math_class *data;

public:
	matrix(int rows, int cols);
	~matrix() { delete [] data; }

	math_class get(int nRow, int nColumn) const;
	bool set(int nRow, int nColumn, math_class value) const;
	
	int getRows() const { return ROWS; }
	int getCols() const { return COLUMNS; }
	int getMatrixNumber() const { return matrix_number; } 
};

template <class math_class>
int matrix<math_class>::next_matrix_number = 1;

template <class math_class>
matrix<math_class>::matrix(int rows, int cols) : ROWS(rows), COLUMNS(cols), matrix_number(matrix::next_matrix_number++) {
	data = new math_class[ROWS * COLUMNS];
}


Was This Post Helpful? 1
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2