1
class matrix
{

public:

    matrix();
    matrix(int row, int column);
    ~matrix();

private:

    const int DEFAULT_SIZE;

    int size_row, size_column;
    double *entry;
};

// main function
int
main()
{
    //make a matrix of default size
    matrix A;   /* no error */
    delete A;

    //make 5 matrices of default size
    matrix *B = new matrix [5]; /* no error */
    delete [] B;

    //make a matrix of size 15x15
    matrix C(15, 15);   /* no error */
    delete C;

    //make 5 matrices of size 15x15
    matrix *D = new matrix(15, 15) [5]; /* compile error !! */


    return 0;
}



//Define functions

matrix::matrix() : DEFAULT_SIZE(10)
{
    size_row = DEFAULT_SIZE;
    size_column = DEFAULT_SIZE;

    entry = new double [size_row*size_column];
}

matrix::matrix(int row, int column) : DEFAULT_SIZE(10)
{
    size_row = row;
    size_column = column;

    entry = new double [size_row*size_column];
}

matrix::~matrix()
{
    delete [] entry;
}

I'm studying about constructor. I'd like to declare arrays by using constructor with variables. Can you correct my code line?

Please see the line below '//make 5 matrices of size 15x15'

Also, in this case, how can I use destructor?

Superlunary
  • 25
  • 1
  • 6
  • possible duplicate of [c++ Object array initialization without default constructor](http://stackoverflow.com/questions/4754763/c-object-array-initialization-without-default-constructor) – user3528438 May 04 '15 at 16:35
  • 2
    Your `delete A;` and `delete C;` lines are incorrect. You only need to `delete` after you've used `new`. – aschepler May 04 '15 at 16:43

2 Answers2

2

To make an array of 5 elements that each get constructed with (15,15), you could do the following in C++11:

matrix* D = new matrix[5]{
    {15,15}, {15,15}, {15,15}, {15,15}, {15,15}
};

But it would be much simpler to just use a vector:

std::vector<matrix> D(5, {15,15});        // C++11
std::vector<matrix> D(5, matrix(15,15));  // pre-C++11
Barry
  • 286,269
  • 29
  • 621
  • 977
0

After looking at your source code here is what I have seen! In your class for your private members your row and column sizes should not be of type int, they should be unsigned int. The reason they should be unsigned int is because an int without an unsigned is a signed value by default which means it can have negative numbers. For the amount of rows and columns in a matrix that does not make sense. With an unsigned int value it ranges from [0, max_value] of an unsigned int. Another thing to take care in is what if someone entered in 0 for either the row or column size or both? Then you would still not have a valid matrix. A little logic needs to be done here; if someone enters in a 0 for either then you have to make a decision as what the default behavior should be. Do you want to use the default value of 10? Also a value of 1x1 does not make sense either! Now you could have 1x4 or 4x1 then these would not be exactly a Matrix but they would be vectors that are either row or column major in order. In my honest opinion your default matrix size from the base constructor without any arguments should be 2x2. If a user specifies 1 for either parameter then the other parameter should be greater then 1. Also there is no need for 2 constructors here, this is duplicate code and can be done with just 1 constructor. Also there is no need to call your destructor, this gets automatically called when this class object goes out of scope.

For matrices would you think that the elements should be public for easy access? Right now as it stands your (element) array is private meaning no outside class can access them, now if this is the behavior you want then you will need functions to access them and to set them if the values need to change.

Based on your class implementation here is what I did to show you the changes I have mentioned above.

#include <vector>
#include <array>

class Matrix {
private:
    const unsigned int DEFAULT_SIZE;
    unsigned int size_row, size_column;
    double* elements;

public:
    explicit Matrix( unsigned int row = 0; unsigned int column = 0 );
    ~Matrix();

    // Copy Constructor
    Matrix( const Matrix& c );
    // Operator = Needed
    Matrix& operator=( const Matrix& c );

}; // Matrix

Matrix::Matrix( unsigned int row, unsigned int column ) : DEFAULT_SIZE(2) {
    // Check if both are 0 Or both are 1 - use default sizes
    if ( (row == 0 && column == 0) ||
         (row == 1 && column == 1) ) {
        row    = DEFAULT_SIZE;
        column = DEFAULT_SIZE;        
    } 

    // Check [Row,Column] For [0,1] && [1,0]
    if ( row == 0 && column == 1 ) { 
        row    = 1;
        column = DEFAULT_SIZE;

    } else if ( row == 1 && column == 0 ) {
        row    = DEFAULT_SIZE;
        column = 1;            
    }

    size_row    = row;
    size_column = column;   

    element = new double[size_row * size_column];    
} // Matrix

Matrix::~Matrix() {
   delete [] elements
} // ~Matrix

Matrix::Matrix( const Matrix& c ) : DEFAULT(2) {
    this->size_row    = c.size_row;
    this->size_column = c.size_column;
    this->element     = c.element;
} // Matrix(copy)

Matrix& Matrix::operator=( const Matrix& c ) {
    // Assignment Can Only Happen If Both Matrices Are Of The Same Dimensions:
    // You can not set a 4x3 = 6x9 for this does not make sense
    if ( (this->size_row    == c.size_row) &&
         (this->size_column == c.size_column) ) {

          this->element     = c.element;
    return *this;
} // operator=

As for the code in your main function I see a few errors that need to be fixed. The first two lines:

Matrix A;
delete A;

You are declaring Matrix A; then on the next line you are calling delete on A. This is your first error: A is an instance of Matrix. This is a local stack variable that belongs to the scope of the main function. There is no need to call delete on this! When your instance of Matrix (A) goes out of scope the Matrix::~Matrix() is called implicitly for you behind the scenes, there is no need to invoke it.

Your next two lines of code:

Matrix* B = new Matrix[5];
delete [] B; 

These two are correct and there are no problems here. You instance B is a pointer to a type object Matrix and because new is used here it is created on the heap and because you have [5] B is not just a pointer to this type but is a pointer on the heap to the first address of you dynamically allocated array. Then you call delete with the [] operator on B which is correct.

Your next two lines of code:

Matrix C(15,15);
delete C;

You are declaring an instance of a Matrix object called C on the stack where you are now using your defined constructor. Again on the second line here there is no need to call delete on C.

As for your last 2 lines of code this is not as simple as trying to do want you want but isn't all that trivial. In order for you to create your dynamic array of Matrices that all have a default size of 15x15 needs a little more work. In order to do this properly you can see from the class implementation that I added a Copy Constructor and an overloaded = operator. There are three steps to achieve this.

// First Step - Create A Single Stack Instance With Size [15,15]
Matrix D = Matrix( 15, 15 );  // This Will Be Used Later To Populate Your Array
// Second Step - Create An Array of 5 Matrices On The Heap
Matrix* E = new Matrix[5]; // Right Now All Five Are Using Default Size 2x2.

// Step Three Now We Update Them Using Our operator=()
for ( unsigned int i = 0; i < 5; i++ ) {
    E[i] = D;
}
// Then Delete the Array
delete [] E; // Only Need To Delete E

However This WILL NOT WORK: Due to how our operator=() is defined! So how do we achieve this? There are two ways and both work. So You Can Remove Matrix E, the for loop and the delete [] E lines. Leave the Matrix D for that will be needed!

The First is easier: If you noticed I included both vector and array from the STL for this case I will use the vector class since it is the most commonly used.

// We already have: Matrix D = Matrix( 15, 15 );
// You Want an Array of 5
std::vector<Matrix>  vMatrices;  // This will create a vector of stack Matrices but at first it will be "EMPTY"
for ( unsigned int i = 0; i < 5; i++ ) {
     vMatrices.push_back( D );
}

// Now You Have A vector of 5 Matrices.

// If You Want Vector of Pointers
std::vector<Matrix*> vpMatrices; 
for ( unsigned int i = 0; i < 5; i++ ) {
    vpMatrices.push_back( &D );
}

// To clean up your vectors you can simply do
vMatrices.clear();
vpMatrices.clear(); 

// The Other Way Would Be To Use std::array but it is less commonly used.
// If You know you will only ever need a set amount this works good
std::array<Matrix, 5> aMatrices;
for ( unsigned int i = 0; i < 5; i++ ) {
    aMatrices.at(i) = D;
}

// For Holding Pointers
std::array<Matrix*, 5> apMatrices;
for ( unsigned int i = 0; i < 5; i++ ) {
    apMatrices.at(i) = &D;
}

// To Clean Up std::array To Be Honest Not really sure for I do not use them
// But using it here just as an illustration that there are plenty of predefined containers
// to use to hold multiple elements of the same data type.

As a final note about your class, you are creating your size of your matrices and have the elements array defined based on size, however being that everything is private, you have no way to populate it or to access it. Keeping it private means you would have to implement functions to do this and considering the nature of matrices either for them to "Store" data or "Function Calls" or Being a Mathematical Object of Calculations and Operations. You do not want the overhead of accessory functions for this would be a performance hit. There is nothing wrong with keeping the size of the row and columns private, for there is no need to access these outside of the class once they have been defined. But your single dimensional array that is representing your MxN matrix should be publicly defined. Also you should have operator[] defined as well.

If you want to see how a basic math library implements matrices take a look at GLM's math library that is written to work with OpenGL shader language GLSL. This library is an Headers Only Library. No need to link or include *.dlls or *.libs. All you need to do is store it into a folder on you computer and set you system to have an environment variable that points to its main folder. Then in you IDE if you are using VS all you have to do in the additional include section of the projects properties is use the environment variable defined. This is for using it! But to just look over its contents you can just down load it to any folder and open any of the *.h files. Then you can see how they implemented Matrix classes! You will notice that they are template types and they have predefined types of matrices such as mat2x2, mat2x3, mat2x4, mat3x2, mat3x3, mat3x4, mat4x2, mat4x3, & mat4x4. This is do to the nature of writing Programs and Shaders that are focused on 2D and 3D Graphics so the min required is a 2x2 and the largest that is truly needed is a 4x4. They also have vector classes defined of different sizes, and your matrices can be constructed from different size vectors. But this should serve as a guideline. Here is their link GLM

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59