Constructor for a class containing a vec of vecs - c++

I'm trying to learn how to create a class which properly initializes a vectors of vectors to implement a matrix. The code below doesn't work, after running the constructor the vector has size 0. The program prints 0 and attempts to access elements of it result in errors.
My first question is what is wrong with the code and how to fix it.
My second question is if there is a better approach to creating a class to implement a matrix dynamically using vectors or similar objects from the STL.
Code:
class Matrix{
std::vector<std::vector<int> > Mat;
public:
Matrix(int n, int m);
void set(int a, int b, int Value);
int get(int a, int b);
void size();
};
Matrix::Matrix(int n, int m){
std::vector<std::vector<int> > Mat(n, vector<int>(m));
}
void Matrix::size(){
std::cout << std::endl << Mat.size() << std::endl;
}
int Matrix::get(int a, int b){
return Mat[a][b];
}
void Matrix::set(int a, int b, int Value){
Mat[a][b]=Value;
}
int main(int argc, char** argv) {
Matrix M(10,10);
M.size();
return 0;
}

1) Current code
The problem is that Mat is already constructed when you enter the body of your constructor. What you do is just redefine a local Mat which hides the member having the same name and which vanishes as soon as you exit the constructor.
Try this instead:
Matrix::Matrix(int n, int m) : Mat(n, vector<int>(m)) {
}
2)Are there better approaches ?
it all depend on what you intend to do, whar atre your constraints, and what are the trade-offs:
If the size of you matrixes is not always defined at compile time, this kind of implementation is fairly good, and the code very readable.
If you have many rather small vectors, one alternative could be to flatten the internal representation of the matrix to a unidimensional vector. You'd spare some vectors, but have to calculate the flatened index for the getter and the setter. If your Matrix class would provide a lot of matrix operations, would make the code less readable (i.e. Mat[n][m] vs. Mat[n*width+m])
If the size of your matrix is determined at compile time (e.g. you use only 2D or 3D matrixes), it could make sense to use std::array instead of std::vector: the compiler could then make use of the known sizes to generate faster code.

This code:
Matrix::Matrix(int n, int m){
std::vector<std::vector<int> > Mat(n, vector<int>(m));
}
will default construct the member-variable Mat, and then, separately, try to construct a local variable Mat, unrelated to the member. To initialize the member variable, you'll want to use a member initializer list:
Matrix::Matrix(int n, int m)
: Mat(n, std::vector<int>(m))
{ }
As a side-note, size() should return the size, not print it, and if your getter returned an int& instead of an int, you wouldn't need a setter with the code duplication.

in the constructor you should initialize using the following instead
Matrix::Matrix(int n, int m) {
Mat = std::vector<std::vector<int> > (n, std::vector<int>(m));
}
or use the way mentioned in the other answers

Related

Templates with pointers, creating 2d array

I got a little problem with templates and pointer. I'm trying to create a 2d array for some different matrices with different types. I have to do it with templates and references where it makes sense.
My main function looks like this, I'm not allowed to change it:
int main(){
int row, column;
cin >> row;
cin >> column;
int** M1;
double** M2;
reserve(M1, row, column);
reserve(M2, row, column);
return 0;
}
So my reserve function would look something like this:
template <typename S>
void reserve(S &x, int row, int column){
x = new S*[row];
for(int i = 0; i < row; ++i) {
x[i] = new S[column];
}
}
My problem is that I'm not getting the solution for this function. I tried it every way I could think about but nothing works.
I think the problem is that I'm not working correct with the type** pointer in combination with the type-parameter. In the version I posted above, im getting errors like:
error: cannot convert ‘int****’ to ‘int**’ in assignment x = new S*[row];
Would love if someone could help me fixing this function.
Changing the signature of reserve to this should fix the compile error
template <typename S>
void reserve(S **&x, int row, int column)
Alternatively, you can implement reserve so that it returns the newly allocated array
template <typename S>
S** reserve(int row, int column)
{
S** x = new S*[row];
for (int i = 0; i < row; ++i) {
x[i] = new S[column];
}
return x;
}
Remember to delete the array using delete [] when you are done using it:)
Maybe something like this might help you; try to encapsulate the whole concept into a class object like this:
template<typename T>
class Matrix {
public:
typedef std::vector<T> Row;
private:
std::vector<Row> Mat;
unsigned numberRows;
unsigned numberColumns;
public:
Matrix();
explicit Matrix( std::vector<Row>& vRows );
Matrix( unsigned numRows, unsigned numColumns );
Matrix( unsigned numRows, unsigned numColumns, T** data );
~Matrix();
private:
void reserve( unsigned int numRows, unsigned int numColumns );
};
Where this reserve() method is part of the class object where only this class has access to it. This would act as a helper function for your class in implementing its multiple constructors. If you want to use dynamic memory for the elements this can be expanded to this:
template<typename T>
class Matrix {
public:
typedef std::vector<std::shared_ptr<T>> Row;
private:
std::vector<Row> Mat;
// All Else Would Be The Same; Only The Internal Methods Would Slightly
// Vary Due To The Use Of Smart Pointer And Dynamic Memory.
};
Then in your main this will simplify code.
int main() {
// Using Default Constructor
Matrix<float> fMat1;
// Using std::vector<Row> To Construct A Matrix
Matrix<int>::Row row1;
Matrix<int>::Row row2;
Matrix<int>::Row row3;
std::vector<Matrix<int>::Row> vRows
Matrix<int> iMat2( vRows );
// A Construct That Knows The Size Of The Matrix;
// But Doesn't Have The Data
Matrix<double> dMat3( 4, 4 ); // This Will Create A Size Of 4x4 Of
// Doubles And Initialize Everything To 0
// Same As Above, But Passing In Raw Data By Double Pointer.
float** pData = nullptr;
// Populate Pointer's Elements
unsigned int row, col;
// Store Size Of Row & Col Based On Pointer's Elements
Matrix<float>( row, col, pData );
return 0;
}
And that is about it! The constructors shouldn't be that hard to implement. And if you are only working with stack objects the first definition of the class will work, but if you need dynamic memory of all objects the second one will suite your needs and the use of smart pointers makes the cleaning up of dynamic memory much cleaner, easier and safer. Less prone to memory leaks.
This would also allow you to create a matrix when you have the data available upon creation of the matrix; or to make an empty matrix container available to set aside memory for later on when you are ready to populate it. You would just have to add the necessary methods to set, get data elements, and any appropriate operator overloads for performing basic operations. Maybe some public methods to do common work on data or to test if data is in matrix, etc.
Because this Matrix class is template the way it is; it is not subject to just basic raw day types. This can store class objects, structure, function pointers, events, threads, files and even more!

What is the equivalent matrix-like C-array of a nested std::vector (for C and C++ interop)?

What is the equivalent matrix-like C-array of a nested std::vector (for C and C++ interop)?
For example, if one wanted to treat std::vector<std::vector<int>> as some kind of int arr[n][m], where n is the dimension of the outer vector and m of the inner vector, then what structure would one use in C?
This is motivated by wanting to have a similar correspondence between matrices in C and C++ as for vectors in:
https://stackoverflow.com/a/1733150/4959635
Based on additional information in the comments, let me suggest you do something like this instead:
class TwoDimVector {
public:
TwoDimVector(int num_cols, int num_rows)
: m_num_cols(num_cols)
, m_num_rows(num_rows)
, m_data(m_num_cols * m_num_rows, 0)
{ }
int & ix(int row, int col) {
return data[num_cols * row + col];
}
const int m_num_rows;
const int m_num_cols;
private:
std::vector<int> m_data;
}
When you do nested vectors, there's a lot of extra work happening. Also, with nested vectors, the data is not contiguous, making it hard to work with any C-apis. Notice with this data structure, the size is fixed at construction time and accessible. This is designed to be row contiguous, so for C interoperability you can access extra raw pointers like so:
TwoDimVector tdv(4,3);
int * raw = &tdv.ix(0,0);
int * raw_second_row = &tdv.ix(1,0);
Just note: if you pass this into a function, be sure to pass by reference:
void do_work(TwoDimVector & tdv) {
...
}
If you don't pass by reference, it will copy everything, which is a bunch of (typically unnecessary) work.
Maybe, this code
void translate(const vector< vector >& vec){
int m = vec.size(), n = 0;
for (vector<int>& deep : vec) // search maximum size if nested vectors
{
if (deep.size() > n)
n = deep.size();
}
int arr[m][n];
m = n = 0;
for (vector<int>& deep : vec){
for (int& x : deep)
{
arr[m][n] = x;
++n;
}
++m;
}
// So, I really don't know how you can return this array :(
}
You see, it code is BAD, you mustn't do it !!!
If you writing on C++ you should using std::vector - it is easier.
C-like arrays is heritage from C, you shouldn't using they

Using a 2-d Array in a function

I am trying to solve a dynamic programming problem and I need to take the user input in the form of a 2-d array and use the values from the 2-d array inside the function.
The values of the 2-d array will not be changed when used inside the function.
In the function int dp i am getting the
error:
declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
int max(int a,int b,int c)
{
if(a>=b && a>=c)return a;
if(b>=c && b>=a)return b;
else return c;
}
int max2(int a,int b)
{
if(a>b)return a;
else return b;
}
int dp(int i,int j,int a[][],int p,int q)
{
if((i-1)>=0 && (j-1)>=0 &&(i+1)<p &&(j+1)<q )
return max(a[i][j]+dp(i-1,j+1,a,p,q),a[i][j]+dp(i+1,j+1,p,q),
a[i][j]+dp(i,j+1,p,q));
if(i==0 && j!=0 && (j+1)<q)
return max2(a[i][j]+dp(i+1,j+1,p,q),a[i][j]+dp(i,j+1,p,q));
}
int main()
{
int p,q,r,s,T,a,b,i,j,k;
scanf("%d",&T);
for(a=0;a<T;a++)
{
scanf("%d %d",p,q);
int z[p][q];
int max=0;
for(i=0;i<q;i++)
{
for(j=0;j<p-1;j++)
scanf("%d ",&z[j][i]);
scanf("%d",&z[j+1][i]);
}
for(i=0;i<p;i++)
{
if(dp(i,0,z,p,q)>max)
max=dp(i,0,z,p,q);
}
}
}
It's all in the error message:
declaration of 'a' as multidimensional array must have bounds for all dimensions except the first
Your function signature does not have bounds for a's 2nd dimension:
int dp(int i,int j,int a[][],int p,int q)
// ^^^^^
You need to fill it in with a[][N] where N is whatever the correct bound is. The issue is that you are using VLAs here:
scanf("%d %d",p,q);
int z[p][q];
That is non-standard C++, and basically means you cannot write the signature of dp, since the second bound has to be known as a compile-time constant. You could either make it a single-dimensional array:
int* z = new int[p*q];
int dp(int i, int j, int* a, int p, int q)
// ^^^^^^
or dynamically allocate it in 2 dimensions and just pass it in that way:
int** z = new int*[p];
for (int i = 0; i < p; ++i) {
z[i] = new int[q];
}
int dp(int i, int j, int** a, int p, int q)
// ^^^^^^^
The function dp needs some information to perform meaningful index calculations, either done by the compiler or in the actual inplementation. Either a dimension must be specified in the type or the argument a could be of type int** while its dimensions are provided as separate arguments to dp. As this is C++, a type of std::vector< std::vector< int > > might be more suitable for the task.
You get that error because you cannot leave both the index(row,column) empty in int a[][] in your function declaration. You must have both specified or atleast the value of column index.
Use dynamic declaration
int **z = new int*[p];
for (int i = 0; i < p; i++)
z[i] = new int[q];
Change the parameter int a[][] to int **a
You can't dynamically declare an array on the stack as the size has to be known at compile time. The only way to do this would be by allocating memory for the array on the heap using the new keyword, then you could declare the size at run time.
Far easier, however, would be just to use a container class, or in your case, a container of containers like a vector of vector of ints;
#include <vector>
vector< vector<int> > arrArray(rows, vector<int>(columns));
The syntax might look a bit strange, but breaking it down;
vector<int> - a vector of type int
vector< vector<int> > - a vector of vectors of type int
arrArray(rows, vector<int>(columns)); - here in the first parameter, we are saying; create rows number of vector<int>'s in our array, and the second parameter initalises the array to some value. If it were just a 2D array of int, we might initalise it to 0, or omit the second parameter and rely on the default value of int. But, because our multidimensional vector also contains vectors, we set each row of our main vector to store a vector of int's which holds columns amount of integers.
Now you can access the array like you would any other;
arrArray[2][0] = 5;
You also get all the added benefits that container classes contain, including iterators and a lot of useful class methods for manipulating and checking your array. Once you understand the syntax of creating container classes, you'll find them much easier to work with than arrays. You also don't have to worry about having to manage your own memory, and have the ability to do bounds checking before accessing vector elements.

c++ overloading operator [] efficiency

I just wanted to know how to overload the operator [] to acces a matrix within a class, and I found how to that here.
But, I have a question about this: Which way of changing a matrix will be more efficient?
1: Overloading the operator []: (code extracted from the previous link)
class CMatrix {
public:
int rows, cols;
int **arr;
public:
int* operator[]( int const y )
{
return &arr[0][y];
}
....
Edit: I relied too much on the other example: Should it work this way?
int* operator[]( int const x )
{
return &arr[x];
}
2:Using a "normal" method:
class CMatrix {
public:
int rows, cols;
int **arr;
public:
void changematrix( int i, int j, int n)
{
arr[i][j]=n;
}
...
Edit: Fixed const on changematrix
Write correct, readable code and let the compiler worry about efficiency.
If you have performance problems, and if when you run a profiler to measure the performance (which you MUST do before trying to optimize) this code shows up as a performance issue, then you can:
1) Examine the assembly language interpretation of the code generated by the compiler with full optimization enabled, or
2) Try it both ways, measure, and pick the faster one.
The results will be highly dependent on the compiler you are using and the flags you specify for that compiler.
Neither method will work as you have declared
int **arr;
gives no row length information for:
return &arr[0][y];
arr[i][j]=n;
I would go for a third option, using operator() instead of operator[]:
int& operator()(size_t i, size_t j) {
return arr[i][j];
}
int operator()(size_t i, size_t j) const {
return arr[i][j];
}
The user will then do:
CMatrix m = ...
m(1,2) = 5;
std::cout << m(1,2);
Other than that, I would really consider whether the way of laying out the data internally the the most efficient. Is this a jagged array? Or do all rows have the same width? If this represents a rectangle shaped array (i.e. all rows have the same number of columns) you might be better off storing all elements in a single 1D array, and using some basic arithmetic to locate the correct element.

Signature for matrix-vector product function

I am relatively new to C++ and still confused how to pass and return arrays as arguments. I would like to write a simple matrix-vector-product c = A * b function, with a signature like
times(A, b, c, m, n)
where A is a two-dimensional array, b is the input array, c is the result array, and m and n are the dimensions of A. I want to specify array dimensions through m and n, not through A.
The body of the (parallel) function is
int i, j;
double sum;
#pragma omp parallel for default(none) private(i, j, sum) shared(m, n, A, b, c)
for (i = 0; i < m; ++i) {
sum = 0.0;
for (j = 0; j < n; j++) {
sum += A[i][j] * b[j];
}
c[i] = sum;
}
What is the correct signature for a function like this?
Now suppose I want to create the result array c in the function and return it. How can I do this?
So instead of "you should rather" answer (which I will leave up, because you really should rather!), here is "what you asked for" answer.
I would use std::vector to hold your array data (because they have O(1) move capabilities) rather than a std::array (which saves you an indirection, but costs more to move around). std::vector is the C++ "improvement" of a malloc'd (and realloc'd) buffer, while std::array is the C++ "improvement" of a char foo[27]; style buffer.
std::vector<double> times(std::vector<double> const& A, std::vector<double> const& b, size_t m, size_t n)
{
std::vector<double> c;
Assert(A.size() = m*n);
c.resize(n);
// .. your code goes in here.
// Instead of A[x][y], do A[x*n+y] or A[y*m+x] depending on if you want column or
// row-major order in memory.
return std::move(c); // O(1) copy of the std::vector out of this function
}
You'll note I changed the signature slightly, so that it returns the std::vector instead of taking it as a parameter. I did this because I can, and it looks prettier!
If you really must pass c in to the function, pass it in as a std::vector<double>& -- a reference to a std::vector.
This is the answer you should use... So a good way to solve this one involves creating a struct or class to wrap your array (well, buffer of data -- I'd use a std::vector). And instead of a signature like times(A, b, c, m, n), go with this kind of syntax:
Matrix<4,4> M;
ColumnMatrix<4> V;
ColumnMatrix<4> C = M*V;
where the width/height of M are in the <4,4> numbers.
A quick sketch of the Matrix class might be (somewhat incomplete -- no const access, for example)
template<size_t rows, size_t columns>
class Matrix
{
private:
std::vector<double> values;
public:
struct ColumnSlice
{
Matrix<rows,columns>* matrix;
size_t row_number;
double& operator[](size_t column) const
{
size_t index = row_number * columns + column;
Assert(matrix && index < matrix->values.size());
return matrix->values[index];
}
ColumnSlice( Matrix<rows,columns>* matrix_, size_t row_number_ ):
matrix(matrix_), row_number(row_number_)
{}
};
ColumnSlice operator[](size_t row)
{
Assert(row < rows); // note: zero based indexes
return ColumnSlice(this, row);
}
Matrix() {values.resize(rows*columns);}
template<size_t other_columns>
Matrix<rows, other_columns> operator*( Matrix<columns, other_columns> const& other ) const
{
Matrix<rows, other_columns> retval;
// TODO: matrix multiplication code goes here
return std::move(retval);
}
};
template<size_t rows>
using ColumnMatrix = Matrix< rows, 1 >;
template<size_t columns>
using RowMatrix = Matrix< 1, columns >;
The above uses C++0x features your compiler might not have, and can be done without these features.
The point of all of this? You can have math that both looks like math and does the right thing in C++, while being really darn efficient, and that is the "proper" C++ way to do it.
You can also program in a C-like way using some features of C++ (like std::vector to handle array memory management) if you are more used to it. But that is a different answer to this question. :)
(Note: code above has not been compiled, nor is it a complete Matrix implementation. There are template based Matrix implementations in the wild you can find, however.)
Normal vector-matrix multiplication is as follows:
friend Vector operator*(const Vector &v, const Matrix &m);
But if you want to pass the dimensions separately, it's as follows:
friend Vector mul(const Vector &v, const Matrix &m, int size_x, int size_y);
Since the Vector and Matrix would be 1d and 2d arrays, they would look like this:
struct Vector { float *array; };
struct Matrix { float *matrix; };