-1

What is the best option to allocate memory for Matrix? I need to allocate memory in the first Mat Constructor . The second Mat Constructor needs 1 argument, when Matrix is considered 1D array, so the number of rows will be 1. I also have to allocate memory in this second constructor.

Matrix data should be double

this is what I have tried:

#include<iostream>

class Mat{
    uint16_t rows;
    uint16_t colls;
    double *mData; // the 2D array// matrix

    Mat(uint16_t r, uint16_t c){ // constructor with 2 parameters -
        // alocating memory for matrix
        this-> rows = r;
        this-> colls = c;
        this-> mData = new double [rows][colls];
    }
    Mat(uint16_t x){ //constructor with 1 parameter // alocating memory
        //for the case when number of rows = 1 , so the matrix becomes 1D array[] 
        this-> rows = x;
        this-> mData = new double [rows];
    }
    
};

I'm not good at pointers, so i can't figure out what I am missing.

"Array size is not a constant expression"

--UPDATE --

Full request: Create the Mat class by implementing its contents as follows:

The class must contain 2 private attributes called mCols andmRows.These are the dimensions of the matrix, and their type is a 16-bit integer without a 16-bit mark.

The class must contain 1 private attribute named mData. This is a pointer to fractional numbers on double precision, and the memory for this pointer will be allocated in the constructor.

A constructor that takes as an argument two unmarked integers that represent the number of lines and the number of columns of an array and allocates memory to store these values.

A second constructor to take as an argument a single number. In this case, the array is considered a vector, the number of lines will be by default 1 and the received argument represents the number of columns. Of course, the allocation of memory to be able to store numbers must also be done in this case.

A third constructor who doesn't take any arguments. It will only initialize the integer attributes with the value of 0.

A fourth constructor, which will be the copy constructor. It receives as an argument an object of type const Mat & and its role is to copy all the values of the attributes of the given object as a parameter in the current object (this).

New code:

class Mat{
private:
    uint16_t mRows;
    uint16_t mCols;
    double *mData;
public:
    Mat(uint16_t r, uint16_t c){
        mRows = r;
        mCols = c;
        mData = new double[mRows * mCols];
    }
    Mat(uint16_t c){
        mCols = c;
        mRows = 1;
        mData = new double [1 * mCols];
    }
    Mat(){
        mRows = 0;
        mCols = 0;
    }
    Mat(const Mat &mat) : mRows(mat.mRows), mCols(mat.mCols), mData(mat.mData){

    }

};
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • 2
    Rather use a `std::vector` sized `rows * cols`, and provide an `uint16_t operator()(int row, int col)` for your `Mat` class. There's plethora of examples on the internet, how to do that. – πάντα ῥεῖ Nov 05 '21 at 19:33
  • 1
    The best option is don't. Use a `std::vector`. [Something like this](https://stackoverflow.com/a/2076668/4581301) is my default starting point for a matrix class. – user4581301 Nov 05 '21 at 19:34
  • request: The class must contain 1 private attribute named mData. This is a pointer to fractional numbers on double precision, and the memory for this pointer will be allocated in the constructor. – Stefan Daniel Nov 05 '21 at 19:37
  • OK. That sucks. You cannot easily allocate a dynamic multi-dimensional array. The usual hack is to make a `double ** mData;` and then allocate an array of double pointers for `mData` and then allocate a buttload of arrays for the array of pointers to point at. This is hilarious and slow, so [do this instead](https://isocpp.org/wiki/faq/operator-overloading#matrix-subscript-op). This is a 1D array that's big enough for all of the dimensions and then does what πάνταῥεῖ and I were recommending above with `vector`, but it does it the hard way. – user4581301 Nov 05 '21 at 19:42
  • Just lookit all the extra smurf you have to do to protect the pointer and the allocation it points at. – user4581301 Nov 05 '21 at 19:45
  • 1
    If the size is known at compile time, and often it is, you can use a template – MatG Nov 05 '21 at 19:51
  • 1
    Side note to help you simplify the code: A 1D array is a 2D array where the size of one of the dimensions is always 1. – user4581301 Nov 05 '21 at 19:55
  • 1
    Do you really need a special case for a single row? Just use the first constructor and pass 1 for rows. – Caleb Nov 05 '21 at 20:05
  • Warning about the copy constructor: `mData(mat.mData)` points the new `Mat`'s data at the same array as the source `Mat`. Change one, you change both. delete one and the other points at a dead array. This is fatal. You want to create a new array the same size as the source's and then copy the items in the source's array to the new array. When you get to writing the copy assignment operator, consider starting with the [Copy and Swap Idiom](https://stackoverflow.com/questions/3279543). Copy and Swap's often overkill, but it's very hard to get wrong and it never fails. – user4581301 Nov 05 '21 at 20:22
  • @Caleb has a good suggestion: See if you can take advantage of [delegating constructors](https://learn.microsoft.com/en-us/cpp/cpp/delegating-constructors?view=msvc-160). Normally I'd suggest a single constructor with a default parameter, but the first parameter cannot be defaulted and the difference between rows and columns may become important later. Plus it's specifically required. – user4581301 Nov 05 '21 at 20:26

1 Answers1

-2

First of all, you need to use double** instead of double* for implementing 2d array

Secondly, I guess you need public constructors(now you have private)

And of course is better to use std::vector, but if you don`t want to, you can use my suggested code:

 Mat(uint16_t r, uint16_t c){ // constructor with 2 parameters -
    // alocating memory for matrix
    this-> rows = r;
    this-> colls = c;
    this->mData = new double*[rows];
    for(int i = 0; i < rows; i++) {
        mData[i] = new double[colls];
    }

}
Oleksandr
  • 35
  • 6
  • 1
    Works, but this is the slow and stupid way. It can be implemented with a `double *`, and the one indirection makes things much, much faster. – user4581301 Nov 05 '21 at 19:46
  • Now that the asker has clarified the question, it is strongly suggested by the program requirements that the asker must use one level of pointer indirection. I don't think the `double**` is viable here. – user4581301 Nov 05 '21 at 20:32