I'm trying to create a template to allocate dynamically an 2D matrix.
Usually what I do is:
float **Allocate_matrix_float (int m, int n)
{
float **v;
int i;
if (m < 1 || n < 1) {
printf ("** Invalid parameter **\n");
return (NULL);
}
v = (float **) calloc (m, sizeof(float *));
if (v == NULL) {
printf ("** Unsufficient memory **");
return (NULL);
}
for ( i = 0; i < m; i++ ) {
v[i] = (float*) calloc (n, sizeof(float));
if (v[i] == NULL) {
printf ("** Unsufficient memory **");
return (NULL);
}
}
return (v);
}
float **free_matrix_float (int m, int n, float **v)
{
int i;
if (v == NULL) return (NULL);
if (m < 1 || n < 1) {
printf ("** invalid parameter**\n");
return (v);
}
for (i=0; i<m; i++) free (v[i]);
free (v);
return (NULL);
}
However I'd like to create a template to allocate any type of 2D matrix. Can anyone help me?
The ideal would be something like:
template<typename T>
T**Allocate_matrix(int n, int m)
...
All of your allocation and deallocation code can be replaced by
std::vector<std::vector<float>> matrix(m, std::vector(n));
Seriously. It even deallocates itself when it goes out of scope, so you have almost no memory management issues.
#include <iostream>
#include <vector>
int main()
{
size_t m;
size_t n;
std::cin >> m >> n;
// floats initialized to 0.0
std::vector<std::vector<float>> fltmatrix(m, std::vector<float>(n));
// doubles initialized to 0.0
std::vector<std::vector<double>> dblmatrix(m, std::vector<double>(n));
// bools initialized to true
std::vector<std::vector<bool>> boolmatrix(m, std::vector<bool>(n), true);
// ints initialized to 42
std::vector<std::vector<int>> intmatrix(m, std::vector<int>(n, 42));
} <-- all vectors are released here.
Practically no effort required.
However, because each vector is it's own independent entity and you have m+1 vectors, you have m+1 different places in memory that your program needs to look to return a value. This can have a really bad impact on your programs performance as small matrices, say a 3x3, can't take full advantage of the CPU's caching and this can be very, very noticeable when crunching large numbers of matrices. If you don't care, stop reading and go with the simple vector of vector approach.
If you do care, wrap a 1D vector in a class:
#include <iostream>
#include <vector>
template<class TYPE>
class Matrix
{
private:
size_t rows, columns;
std::vector<TYPE> matrix;
public:
Matrix(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), matrix(rows * columns)
{
}
Matrix(size_t numrows, size_t numcols, TYPE init) :
rows(numrows), columns(numcols), matrix(rows * columns, init)
{
}
TYPE & operator()(size_t row, size_t column)
{
// check bounds here
return matrix[row * columns + column];
}
TYPE operator()(size_t row, size_t column) const
{
// check bounds here
return matrix[row * columns + column];
}
size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
friend std::ostream & operator<<(std::ostream & out, const Matrix & in)
{
for (int i = 0; i < in.getRows(); i++)
{
for (int j = 0; j < in.getColumns(); j++)
{
out << in(i, j) << ' ';
}
out << std::endl;
}
return out;
}
};
int main()
{
size_t m;
size_t n;
std::cin >> m >> n;
// floats initialized to 0.0
Matrix<float> fltmatrix(m, n);
std::cout << fltmatrix << std::endl;
// doubles initialized to 0.0
Matrix<double> dblmatrix(m, n);
std::cout << dblmatrix << std::endl;
// bools initialized to true
Matrix<bool> boolmatrix(m, n, true);
std::cout << boolmatrix << std::endl;
// ints initialized to 42
Matrix<int> intmatrix(m, n, 42);
std::cout << intmatrix << std::endl;
}
More effort, but should be faster. Profile your program to see if Matrix is right for you.
operator<< is included as an output convenience and as an example of how to access Matrix's cells.
And if you just have to use an array... Things get a lot uglier. For one thing, you will have to be Rule of Three (and possibly Rule of Five) compliant and pick up a bunch of extra functions that, frankly, you're probably not going to get right the first few times.
I'm not even sure I can get it right if I just bang one out, and I have a perfectly good alternative, so I'm not going to. What you can gain is a matrix that does not spend time initializing the matrix before use. If that is an issue (profile, profile, profile!) I'd call that a new question. The current question uses calloc so it doesn't look like OP is concerned.
As paddy mentions here using vector-of-vector is not practical, difficult to change and suffers from cache misses. As well as using bare pointers is impractical in terms of C++ which provides better tools like operator overloading.
Taking paddy's implementation as basis your 2d matrix can be implemented in the following way:
template <class T>
class SimpleMatrix
{
public:
SimpleMatrix( int rows, int cols, const T& initVal = T() )
: m_data( rows * cols, initVal )
, m_rows( rows )
, m_cols( cols )
{
}
// Direct vector access and indexing
operator const vector<T>& () const { return m_data; }
int Index( int row, int col ) const { return row * m_cols + col; }
// Get a single value
T & Value( int row, int col ) { return m_data[Index(row,col)]; }
const T & Value( int row, int col ) const { return m_data[Index(row,col)]; }
// Proxy structure to allow [][] indexing
struct Proxy
{
private:
friend class SimpleMatrix<T>;
SimpleMatrix<T>* m_matrix;
int m_row;
Proxy( SimpleMatrix<T>* m, int row ) : m_matrix(m), m_row(row) {}
public:
T & operator[] ( int col ) { return m_matrix->Value(m_row, col); }
const T & operator[] ( int col ) const { return m_matrix->Value(m_row, col); }
};
Proxy operator[]( int row ) { return Proxy(this, row); }
const Proxy operator[]( int row ) const { return Proxy(const_cast<SimpleMatrix<T>*>(this), row); }
private:
vector<T> m_data;
int m_rows;
int m_cols;
};
And use it in the following way:
SimpleMatrix<int> m(10, 2);
const SimpleMatrix<int>& cm = m;
m[1][1] = 1;
cout << cm[1][1];
This will also allow you to check the boundaries of the index.
Related
I have the following problem:
I've a precomputed 2d matrix of values which i need to lookup very often and compute only once
The size of the matrix is about 4000x4000 at most
The matrix won't be sparse, i typically need almost all values.
The values in the matrix can be boolean, integer or double. At least they are always small objects
Currently i am storing the precomputed values in a std::vector<<std::vector<T>>, and i've noticed the lookups into this datastructure takes quite some time in heavy computations. I've googled around and so far the suggested implementation seems to be to try a solution in which all the memory is stored contigious using an 1D array where the location in this array is computed based on i and j.
Does anybody have a good example implementation of this or has an even better suggestion? I couldn't find a modern C++ example, while it seems to be a very common problem to me. I'd prefer to use someone elses code instead of reinventing the wheel here. Of course i will measure the differences to see whether it actually improves performance.
Examples i've found:
https://medium.com/#patdhlk/c-2d-array-a-different-better-solution-6d371363ebf8
https://secure.eld.leidenuniv.nl/~moene/Home/tips/matrix2d/
Here is a very simple and efficient 2-d matrix. The 'main' creates a 10000x10000 double array 'mat', then filled it with random number. The array 'mat' is copied into another array 'mat2'. your may input two integers 'n' and 'm' between 0 and 9999 to fetch the double data at mat2(n,m).
Feel free to use or test it. Let me know if you encounter problems or need some more functions to be implemented. Good luck!
#ifndef ytlu_simple_matrix_class_
#define ytlu_simple_matrix_class_
#include <iostream>
#include <iomanip>
#include <complex>
template <typename T> class tMatrix
{
public:
T *ptr;
int col, row, size;
inline T* begin() const {return ptr;}
inline T* end() const {return this->ptr + this->size;}
inline T operator()(const int i, const int j) const { return ptr[i*col+j];
} // r-value
inline T&operator()(const int i, const int j) { return ptr[i*col+j]; } //l-value
inline tMatrix(): col{0}, row{0}, size{0}, ptr{0} {;}
tMatrix(const int i, const int j): col(j), row(i), size(i*j)
{
ptr = new T [this->size] ;
}
tMatrix(const tMatrix<T>&a) : tMatrix<T>(a.row, a.col)
{
std::copy(a.begin(), a.end(), this->ptr);
}
tMatrix<T>& operator=(tMatrix<T>&&a)
{
this->col = a.col;
this->row = a.row;
delete [] this->ptr;
this->ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
tMatrix<T>& operator=(const tMatrix<T>&a)
{
if (col==a.cpl && row==a.row) std::copy(a.begin(), a.end(), this->ptr);
else { tMatrix<T>&&v(a); *this = std::move(v);}
return *this;
}
~tMatrix() {delete [] this->ptr;}
}; //end of class tMatrix
template <typename X> std::ostream& operator<<(std::ostream&p, const tMatrix<X>&a)
{
p << std::fixed;
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(12) << a(i, j);
p << std::endl;
}
return p;
}
using iMatrix = tMatrix<int>;
using rMatrix = tMatrix<double>;
using cMatrix = tMatrix<std::complex<double> >;
#endif
//
//
#include <ctime>
#include <cstdlib>
#define N1 10000
int main()
{
int n, m;
std:srand(time(NULL)); // randomize
rMatrix mat(N1, N1); // declare a 10000 x 10000 double matrix
//
// fill the whole matrix with double random number 0.0 - 1.0
//
for (int i = 0; i<mat.row; i++)
{ for (int j=0; j<mat.col; j++) mat(i, j) = (double)std::rand() / (double)RAND_MAX; }
//
// copy mat to mat 2 just for test
//
rMatrix mat2 = mat;
//
// fetch data test input 0 <= n m < 10000 to print mat2(n, m)
//
while(1)
{
std::cout << "Fetch 2d array at (n m) = ";
std::cin >> n >> m;
if ((n < 0) || (m < 0) || (n > mat2.row) || (m > mat2.col) )break;
std::cout << "mat(" << n << ", " << m << ") = " << mat2(n, m) << std::endl << std::endl;
}
return 0;
}
The compile parameter I used and the test run. It takes a couple seconds to fill the random numbers, and I felt no lapse at all in fetch a data running in my aged PC.
ytlu#ytlu-PC MINGW32 /d/ytlu/working/cpptest
$ g++ -O3 -s mtx_class.cpp -o a.exe
ytlu#ytlu-PC MINGW32 /d/ytlu/working/cpptest
$ ./a.exe
Fetch 2d array at (n m) = 7000 9950
mat(7000, 9950) = 0.638447
Fetch 2d array at (n m) = 2904 5678
mat(2904, 5678) = 0.655934
Fetch 2d array at (n m) = -3 4
Is there a way to tell the compiler that I've allocated a memory of size N * M and I wanna treat this pointer as N * M array? In other words, is there a way to write something like this?:
int arr[N][M] = (int[N][M])malloc(N * M * sizeof(int));
arr[x][y] = 123;
I know that the compiler doesn't know the dimensions of the array, all it knows is that that's a pointer. so my question is: can I somehow tell the compiler that this pointer returned by malloc is an array pointer and it's dimensions are N * M? I can use an array to pointers, pointer to arrays or pointer to pointers, but in all cases I'll have to lookup 2 addresses. I want to have a contiguous memory on the heap and treat it as a multidimensional array. just like how I would write:
int arr[N][M];
Is there any way to achieve that?
In a C++ program you should use the operator new.
As for malloc then in C++ M shall be a constant expression if you want to allocate a two-dimensional array.
You can write for example
int ( *arr )[M] = ( int ( * )[M] )malloc( N * M * sizeof(int) );
or
int ( *arr )[M] = ( int ( * )[M] )malloc( sizeof( int[N][M] ) );
If to use the operator new then the allocation can look like
int ( *arr )[M] = new int[N][M];
If M is not a compile-time constant then you can use the standard container std::vector as it is shown in the demonstrative program below
#include <iostream>
#include <vector>
int main()
{
size_t n = 10, m = 10;
std::vector<std::vector<int>> v( n, { m } );
return 0;
}
What you want is a "matrix" class like
template <typename T>
class matrix
{
size_t len;
size_t width;
std::vector<T> data;
public:
matrix(size_t len, size_t width) : len(len), width(width), data(len*width) {}
T& operator()(size_t row, size_t col) { return data[width * row + col]; }
const T& operator()(size_t row, size_t col) const { return data[width * row + col]; }
size_t size() const { return len * width; }
};
int main(int argc, char const *argv[])
{
matrix<int> m(5, 7);
m(3, 3) = 42;
std::cout << m(3, 3);
}
This keeps all of the data in a single contiguous buffer, and doesn't have any undefined behavior unlike all the other examples that use malloc. It's also RAII, and you don't have to write any copy or move constructors since all of the members "do the right thing" with the compiler provided defaults. You can make this class more complicated, provide a proxy object so you can overload operator[] and be able to do m[][], but at it's base this is what you want.
If you what to avoid use of stack and you need large single block of data to keep two dimensional array of constant size (know at compile time) the this is the best cleanest way to do it:
std::vector<std::array<int, M>> arr(N);
arr[x][y] = 3;
Now if you need M is a value known at run-time, it would be best to use boost::multi_array
I do not see a reason to use malloc.
You can do exactly what you want with a helper function. This let's you specify the array size at runtime, and it uses malloc as requested (although typically you should be using new):
#include <iostream>
#include <string>
#include <memory>
template <class T>
T** Get2DMalloc(size_t m, size_t n) {
T** ret = (T**)malloc(sizeof(T*) * m);
for (size_t i = 0; i < m; ++i) {
ret[i] = (T*)malloc(sizeof(T) * n);
}
return ret;
}
template <class T>
void Free2D(T** arr, size_t m, size_t n) {
for (int i = 0; i < m; ++i) {
free(arr[i]);
}
free(arr);
}
int main() {
int m = 3;
int n = 3;
int** a = Get2DMalloc<int>(3, 3);
for (int x = 0; x < m; ++x) {
for (int y = 0; y < n; ++y) {
a[x][y] = x * m + y;
}
}
for (int i = 0; i < m * n; ++i) {
std::cout << a[i / m][i % n] << std::endl;
}
Free2D<int>(a, m, n);
system("pause");
return 0;
}
Arrays have this nice property of being contiguous blocks of memory. When using new to allocate memory for an array, it returns a pointer to a contiguous block of memory. However, if I allocate a matrix using new, like this:
#include <iostream> //std::cin
int main()
{
int n, m;
std::cin >> n >> m;
int** mat = new int*[n];
for (int i = 0; i < n; i++)
mat[i] = new int[m];
//use the matrix in some way
for (int i = 0; i < n; i++)
delete[] mat[i];
delete[] mat;
return 0;
}
This works, but mat doesn't point to a contiguous block of size n * m * sizeof(int). How can I do this in C++? I am just complying to the latest standard (that is C++17) and nothing else. I want an answer that doesn't involve STL containers or external libraries.
Please don't answer about C, as that is pretty easy to do in both C99 and C11 using variable-length arrays:
#include <stdio.h> //scanf
#include <stdlib.h> //malloc, free
int main()
{
int n, m;
scanf("%d %d", &n, &m);
//int mat[n][m]; VLA, but I want dynamic
int (*mat)[m] = malloc(n * sizeof *mat);
//use the matrix in some way;
free(mat);
return 0;
}
Here's what you were doing, almost exactly the same but without the non-contiguous memory:
#include <iostream> //std::cin
#include <memory>
int main()
{
int n, m;
std::cin >> n >> m;
auto matrix_data = std::make_unique<int[]>(n * m);
auto mat = std::make_unique<int[]>(n);
for(int i = 0; i < n; i++) { mat[i] = matrix_data.get() + i * m; }
// Use the matrix in some way
// No need to free anything - we're using smart pointers.
// No need to return 0 from main - that's the default
}
Notes:
This is still ugly code... you'd likely better create a proper matrix class, or better still - use somebody else's implementation.
It is better to follow #Someprogrammerdude's suggestion and use arithmetic rather than an array of pointers.
I kind of still don't know what particularly are you asking for. To store matrix elements in a contiguous location, simply allocate the memory for them as a one-dimensional dynamic array. The two basic options have been already discussed, either use a vector:
std::vector<int> mat(m * n);
or, if its memory overhead is significant for you, use a unique pointer:
auto mat = std::make_unique<int[]>(m * n);
Then, to access an element with i row index and j column index, simply use:
a_i_j = mat[i * n + j];
assuming m is the number of rows and n is the number of columns. This formula stores elements in so-called row-major order. If you need the column-major order, switch to:
a_i_j = mat[j * m + i];
Of course, whole approach would be much better encapsulated in a class with some getter operator mat(i, j);.
Here is a 2D matrix class that enables m[i][j] support and has a contiguous storage. It contains a minimalistic set of member functions to create and access elements.
It's a shame that the STD library does not provide such functionality. [i][j] element access is way less error prone than index arithmetics.
#include <cstddef>
#include <vector>
template <typename T>
class matrix
{
public:
using value_type = T;
private:
class row_view
{
public:
constexpr row_view(size_t length, value_type *begin)
: _length(length),
_begin(begin)
{}
value_type &operator[](size_t i) {
// TODO: check bounds
return *std::next(_begin, i);
}
const value_type &operator[](size_t i) const {
// TODO: check bounds
return *std::next(_begin, i);
}
size_t size() const {
return _length;
}
private:
size_t _length;
value_type *_begin;
};
public:
matrix(size_t rows, size_t cols, value_type &&defaultVal)
: _rows(rows),
_array(rows * cols, std::move(defaultVal))
{}
matrix(size_t rows, size_t cols)
: matrix(rows, cols, value_type{})
{}
size_t rows() const noexcept {
return _rows;
}
size_t cols() const noexcept {
return _array.size() / _rows;
}
auto operator[](size_t rowIndex) -> row_view{
const size_t offset = cols() * rowIndex;
return {cols(), &_array[offset]};
}
auto operator[](size_t rowIndex) const -> const row_view{
const size_t offset = cols() * rowIndex;
return {cols(), &_array[offset]};
}
private:
size_t _rows;
std::vector<value_type> _array;
};
https://godbolt.org/z/qoG6jGbh5
int** transpose(int** matrix,int row, int column)
{
int** new_mat = new int*[column];
for(int i = 0; i < column; i++)
{
new_mat[i] = new int[row];
}
for(int i = 0; i < row; i++ )
{
for(int j = 0; j < column; j ++)
{
new_mat[j][i] = matrix[i][j];
}
}
return new_mat;
}
I have written this function but something feels wrong I couldn't decide whether should I delete new_mat somehow basically function returns this value how should I manage with memory without using any smart pointers or something?
The caller would use the returned matrix.
Moreover, it could acquire ownership. As a result, when the matrix would be no longer needed, it could delete it.
Another option, is for you, to provide another function, that will delete the matrix. The caller then, must call that function to de-allocate the dynamically allocated memory.
However, smart pointers is a nice C++ feature, and I encourage you to give them a shot.
Furthermore, since this C++, you could use a std::vector<std::vector<int>> for the type of your matrix. That way, you don't have to worry about memory management, since everything about it, will happen automatically.
To answer the question as asked, the caller would need to release the returned pointer. For every usage of operator new in the function, there needs to be a corresponding usage of operator delete in the caller. The caller would do this when the matrix returned is no longer needed i.e. anything that is deleted should not subsequently be used.
A better approach - in many respects, including no potential to forget to release memory - is to avoid using pointers directly, avoid using operator new (or variants) or operator delete directly. Instead, use a standard container, such as std::vector(std::vector<int> >. If used carefully, standard containers manage their own elements, and keep a record of their own size, so there is no possibility of memory leak (when a standard container ceases to exist, any dynamically allocated memory it uses also is released).
In principle, you should be able to simplify your function to something that is declared as
std::vector<std::vector<int> > transpose(const std::vector<std::vector<int> > &matrix);
rather than needing to pass numbers of rows and columns as separate arguments (the vectors will keep track). I'll leave implementing that function as an exercise, since you'll learn more of use that way.
You really should think about your matrix representation:
int** matrix = ...; // create matrix of 10x12
// doing quite a lot of stuff
delete[] matrix[7]; // possibly even forgotten -> memory leak
matrix[7] = new int[7];
and you now have a jagged array. Although std::vector will relieve you from all the memory management stuff, you still won't be able to prevent jagged arrays with:
std::vector<std::vector<int>> matrix = ...; // create matrix of 10x12
// doing quite a lot of stuff
matrix[7].resize(7);
Safest thing you can do is create your own class wrapping around the data; I'll be using std::vectors to hold the data, this will make the whole memory management stuff much easier:
template <typename T> // more flexibility: you can use arbitrary data types...
class Matrix // (but you don't _need_ to make a template from)
{
std::vector<std::vector<T>> data;
public:
Matrix(size_t rows, size_t columns)
: data(rows)
{
for(auto& d : data)
d.resize(columns);
}
// the nice thing about using std::vector as data container is
// that default generated move/copy constructors/assignment
// operators and destructor are fine already, so you can forget
// about rule of three or five respectively
// but you need ways to access your data:
size_t rows() { return data.size(); }
size_t columns() { return data.empty() ? 0 : data[0].size(); }
??? operator[](size_t index);
??? operator[](size_t index) const;
};
Well, the index operators... What you actually want to achieve is something that you can access the matrix just like you did with your arrays:
Matrix<int> m(10, 12);
m[7][7] = 7;
But what should we return? A reference to an inner vector would again allow to modify its size and to create a jagged array this way. Solution: A wrapper class around!
template <typename T>
class Matrix
{
// all we had so far...
template <typename Data>
class Row
{
Data& data;
friend class Matrix;
Row(std::vector<T>& data)
: data(data)
{ }
public:
// default constructed constructors/operators/destructor
// themselves and being public are fine again...
auto& operator[](size_t index) { return data[index]; }
};
auto operator[](size_t index) { return Row(data[index]); }
auto operator[](size_t index) const { return Row(data[index]); }
};
Why Row a template? Well, we need different Row types (mutable and immutable access to data) as return types for the two different index operators...
Finally: If you implement yourself, I'd reorder the private/public sections such that public comes first. This improves readability for users of your Matrix class, as they are interested in public interface only (normally) unless they intend to inherit from. But that (currently) is not a good idea here anyway as this class is not intended for, just as std::vector is not either. If you want that: make the destructor virtual:
virtual ~Matrix() = default;
If you feel more comfortable with, you could make the rule of three/five explicit:
Matrix(Matrix const& other) = default; // rule of three
Matrix& operator=(Matrix const& other) = default; // rule of three
Matrix(Matrix&& other) = default; // rule of five
Matrix& operator=(Matrix&& other) = default; // rule of five
Analogously for Row class. Be aware that if you insist on using raw arrays inside then you will have to write all of these explicitly!
Transposing matrices could then be done via a free function again:
Matrix transpose(Matrix const& m)
{
Matrix t(m.columns(), m.rows());
// loops as you had
return t;
}
You could even provide a member function that transposes the matrix itself, best: use above transpose function:
template <typename T>
class Matrix
{
public:
void transpose()
{
Matrix t(transpose(*this));
t.data.swap(data); // cleanup of previously owned data done in t's destructor...
}
If you don't want to use any smart pointers and vectors, then try like this.
matrix - is a wrapper for 2D-dynamic array with size [col][row].
#include <iostream>
#include <algorithm>
using namespace std;
class matrix
{
private:
unsigned int m_row;
unsigned int m_col;
int **m_data;
public:
matrix(unsigned int row, unsigned int col) : m_row(row), m_col(col), m_data(nullptr)
{
alloc();
}
matrix(const matrix &m) : m_row(m.get_rows_count()), m_col(m.get_cols_count()), m_data(nullptr)
{
alloc();
for(unsigned int i = 0; i < m_row; i++)
for(unsigned int j = 0; j < m_col; j++)
m_data[i][j] = m[i][j];
}
~matrix()
{
free();
}
unsigned int get_rows_count() const { return m_row; }
unsigned int get_cols_count() const { return m_col; }
const int* operator[](unsigned int ind) const
{
return m_data[ind];
}
int* operator[](unsigned int ind)
{
return m_data[ind];
}
matrix& operator=(const matrix &m)
{
free();
m_row = m.get_rows_count();
m_col = m.get_cols_count();
alloc();
for(unsigned int i = 0; i < m_row; i++)
for(unsigned int j = 0; j < m_col; j++)
m_data[i][j] = m[i][j];
return *this;
}
// you need move-operations:
//matrix(matrix&& other) = delete; // move constructor (rule of 5)
//matrix& operator=(matrix&& other); // move assignment (rule of 5)
void print()
{
for(unsigned int i = 0; i < m_row; i++)
{
for(unsigned int j = 0; j < m_col; j++)
cout << m_data[i][j] << " ";
cout << endl;
}
}
private:
void alloc()
{
if(m_data)
return;
m_data = new int*[m_row];
for(unsigned int i = 0; i < m_row; i++)
{
m_data[i] = new int[m_col];
std::fill(m_data[i], m_data[i] + m_col, 0);
}
}
void free()
{
if(!m_data)
return;
for(unsigned int i = 0; i < m_row; i++)
delete[]m_data[i];
delete[]m_data;
m_data = nullptr;
}
};
matrix transpose(const matrix matrix_in)
{
unsigned int M = matrix_in.get_rows_count();
unsigned int N = matrix_in.get_cols_count();
matrix out(N, M);
for(unsigned int i = 0; i < M; i++)
for(unsigned int j = 0; j < N; j++)
out[j][i] = matrix_in[i][j];
return out;
}
int main(int argc, char* argv[])
{
matrix m1(5, 7);
m1[0][1] = m1[0][2] = m1[0][3] = 7;
auto m2 = transpose(m1);
m1.print();
cout << endl;
m2.print();
}
In any case, it is better to free the memory in the same place where it was allocated. If you do not want to use some classes, you can do it like this:
void transpose(int **matr_in, int **matr_out, int M, int N)
{
for(int i = 0; i < M; i++)
for(int j = 0; j < N; j++)
matr_out[j][i] = matr_in[i][j];
}
int **create_matrix(int M, int N)
{
int **m = new int*[M];
for(int i = 0; i < M; i++)
m[i] = new int[N];
return m;
}
void delete_matrix(int **m, int M)
{
for(int i = 0; i < M; i++)
delete []m[i];
delete []m;
}
int main()
{
int M = 5, N = 4;
int **m1 = create_matrix(M, N);
// fill matrix m1
int **m2 = create_matrix(N, M);
transpose(m1, m2, M, N);
delete_matrix(m1, M);
delete_matrix(m2, N);
return 0;
}
you provide a function return a pointer array which holds seperated memory blocks (each represents one row). then you must also provide the free (or delete) function at the same time, and in the same module (to ensure the memory managerment functions matches exactly).
int** transpose(int** matrix, int row, int column)
{
int** new_mat = new int*[column];
...
return new_mat;
}
//when free the mat, cols is not concerned;
void free_mat(int** matrix, int rows)
{
int i;
for(i= 0; i< rows; i++)
delete[] matrix[i];
delete[] matrix;
}
//use the function as:
int** m2 = transpose(m1, rows, cols);
...
free_mat(m2, cols);
//after free_mat(), m2 still holds the address.
//so make it nullptr.
m2 = NULL;
also you can allcate one plane continuous memory block to present 2-dimention matrix:
int* mat = new int[rows * cols];
//transfer mat[iRow][iCol] to mat[iRow * cols + iCol];
return mat;
First, I'm sorry, I don't know a lot of c++, maybe my question is kind of stupid.
I have a multidimensional vector M. I want to be able to apply the same function either along the elements of a row i, or along the elements of a column j. I don't want to write the same function twice. It is possibly to do this in a rather simple way, like some overloading or with virtual iterators? can anyone write a simple example? thank you.
You can define you own iterator over the columns, so that you can use standard algorithms (like for_each, or transform as mentionned in another answer) to apply you function either to rows or columns of you array by just changing the iterators:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
// Custom iterator to iterate over columns
// to be adapted to the underlying storage
class ColIterator : public std::iterator<std::forward_iterator_tag, double>
{
public:
typedef std::vector<std::vector<double> > MDarray;
ColIterator(MDarray & array, int i, int j) : array_(array), i_(i), j_(j) {}
ColIterator(const ColIterator& it) : array_(it.array_), i_(it.i_), j_(it.j_) {}
ColIterator& operator++() {
++i_;
return *this;
}
ColIterator operator++(int) {
ColIterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const ColIterator& rhs) { return &array_==&rhs.array_ && i_==rhs.i_ && j_==rhs.j_; }
bool operator!=(const ColIterator& rhs) { return !operator==(rhs); }
double& operator*() {return array_[i_][j_];}
private:
MDarray & array_;
int i_;
int j_;
};
// a function
void mult2 (double & x) {
x *= 2;
}
int main () {
typedef std::vector<double>::iterator RowIterator;
int nRows = 5;
int nCols = 5;
ColIterator::MDarray array (nRows, std::vector<double>(nCols, 1));
// Apply function mult2 to column 3
int col = 3;
ColIterator beginCol (array, 0, col);
ColIterator endCol (array, nRows, col);
std::for_each(beginCol, endCol, mult2);
// Apply function mult2 to row 4
int row = 4;
RowIterator beginRow (array[row].begin());
RowIterator endRow (array[row].end());
std::for_each(beginRow, endRow, mult2);
// Check results
for (int i=0 ; i<nRows ; ++i) {
for (int j=0 ; j<nCols ; ++j) {
std::cout << " " << array[i][j];
}
std::cout << std::endl;
}
return 0;
}
A good way to go about this would be to use std::transform. Consult this link for more details. Short example with how to do this for rows is below. The column part is a little tricky.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int nRowCnt = 3, nColCnt = 3;
int RowFunc(int i) { return ++i; }
int ColFunc(int i) { return --i; }
void PrintArray(vector<vector<int>>& vecArray, int nRowCnt, int nColCnt)
{
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
for (int nInner = 0; nInner < nColCnt; nInner++)
{
cout<<vecArray[nOuter][nInner]<<" ";
}
cout<<endl;
}
}
int main()
{
vector< vector<int> > vecVals(nRowCnt, vector<int>(nColCnt,0));
vector< int > rowOut(nColCnt*nRowCnt,0), colOut(nColCnt*nRowCnt,0);
vector<int>::iterator itrOut;
for (int nRow = 0; nRow < nRowCnt; nRow++)
{
for (int nCol = 0; nCol < nColCnt; nCol++)
{
vecVals[nRow][nCol] = nRow * (10+nCol) ;
}
}
PrintArray(vecVals,nRowCnt,nColCnt);
itrOut = rowOut.begin();
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
std::transform(vecVals[nOuter].begin(),vecVals[nOuter].end(),itrOut,RowFunc);
itrOut += nColCnt;
}
itrOut = colOut.begin();
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
for (int nInner = 0; nInner < nColCnt; nInner++)
{
std::transform( vecVals[nInner].begin() + nOuter, vecVals[nInner].begin() + nOuter +1, itrOut,ColFunc);
itrOut++;
}
}
cout<<endl<<"Row Transformed"<<endl;
for (itrOut = rowOut.begin(); itrOut != rowOut.end(); itrOut++)
cout<<*itrOut<<" ";
cout<<endl<<"Col Transformed"<<endl;
for (itrOut = colOut.begin(); itrOut != colOut.end(); itrOut++)
cout<<*itrOut<<" ";
cout<<endl;
return 0;
}
There is a catch though, the column part won't work for non-square 2D arrays (i.e for it to work row and column counts must be the same). I guess this can be worked around with a little more thought.
If your multidimensional vector is an actual multidimensional vector, for example something like std::vector<std::vector<int>>, which isn't suggested, then you will have to write your own iterator. It's not very complicated. Boost.Iterator has concepts that can be used to help implement it.
If your multidimensional vector is a single vector with it's size set to the product of the dimensions (i.e. width * height), which is the preferred way to handle this, then it's much easier. It can be done with the utilities provided by Boost.Range.
Here's a quick and dirty example of using Boost.Range. It could be made a little prettier with decltype. If your compiler doesn't support C++11 (specifically auto), I wouldn't suggest using this, because the code becomes very hard to read.
template<typename T>
boost::iterator_range<typename T::iterator>
GetRow(T& vec, typename T::size_type row, typename T::size_type w,
typename T::size_type h) {
return boost::make_iterator_range(
vec.begin() + (row * w),
vec.begin() + ((row + 1) * w)
);
}
template<typename T>
boost::strided_range<boost::iterator_range<typename T::iterator>>
GetColumn(T& vec, typename T::size_type col, typename T::size_type w,
typename T::size_type h) {
boost::iterator_range<typename T::iterator> range = boost::make_iterator_range(
vec.begin() + col,
vec.begin() + col + (h - 1) * w + 1
);
return boost::strided_range<boost::iterator_range<typename T::iterator>>(w, range);
}
And then using these functions is pretty easy, though again, it can become very ugly if your compiler doesn't support auto.
const size_t WIDTH = 3;
const size_t HEIGHT = 3;
std::vector<int> vec(WIDTH * HEIGHT);
// Fill the first row with 1.
auto row = GetRow(vec, 0, WIDTH, HEIGHT);
for (auto it = row.begin(); it != row.end(); ++it) {
(*it) = 1;
}
// Fill the second column with 2.
auto col = GetColumn(vec, 1, WIDTH, HEIGHT);
for (auto it = col.begin(); it != col.end(); ++it) {
(*it) = 2;
}
// Contents of vec is:
// 1 2 1
// 0 2 0
// 0 2 0
You may also want to look into Boost.MultiArray, which is a library intended for things like this. It provides the functionality you want, but it's definitely not the friendliest library.
For a 2D vector:
Rows will be straightforward:
const std::vector<int>& getRow( const std::vector<std::vector<int>>& input, int rowIdx )
{
return input.at( rowIdx );
}
Columns a little trickier:
std::vector<int> getColumn( const std::vector<std::vector<int>>& input, int colIdx )
{
std::vector<int> output;
for ( unsigned i = 0; i < input.size(); ++i )
output.push_back( input.at( i ).at( colIdx ) );
return output;
}
These functions basically take a 2D integer vector and return a row/column vector based on the specified index.
This is the basis for what you're trying to do (from what I can gather). Minor modification will allow you to apply a function to rows/columns selectively instead of merely returning them.