How to implement operator[][] for 1D arrays - c++

Is there a way to implement an operator like [][] for a 1D array?
I want to change the implementation of a 2D vector to a 1D vector in my code (cause this increases the execution speed by about %50 in my program). 2D vector supports [y][x]. How can I have such functionality for a 1D vector?
I can do it like this:
const size_t Y_Axis { 20 };
const size_t X_Axis { 30 };
std::vector<char> vec( Y_Axis * X_Axis );
size_t row { 5 };
size_t col { 28 };
vec[ row * X_Axis + col ] = 't'; // assign a value to a specific row-column
However, typing this formula multiple times throughout a source file seems like violating DRY (don't repeat yourself). How can I do this in an efficient and idiomatic way? I want to hide the complexity and make things a bit abstracted just like operator[][] of 2D vector does.

C++ does not allow virtual containers. So the operator [] is expected to return a true object of the expected size, if you want all the goodies like true iterators to work smoothly.
Here is a post of mine about the iterator question for multi-dimensional containers and a more general question on Code Review
If you only want to build an operator[](int) that returns something that can accept a second [], it can easily be done for a 2D vector, by returning a plain pointer inside the internal data array of a vector:
template <typename T>
class vec2d {
std::vector<T> data;
size_t _cols;
public:
vec2d(int rows, int cols, T* src = nullptr)
: data(rows * cols), _cols(cols) {
if (src != nullptr) {
for (T& val : data) {
val = *src++;
}
}
}
T* operator [] (size_t row) {
return data.data() + row * _cols;
}
const T* operator [] (size_t row) const {
return data.data() + row * _cols;
}
size_t rows() const {
return data.size() / _cols;
}
size_t cols() const {
return _cols;
}
};
And here is an example usage:
int main() {
vec2d<char> v(3, 4, "ABCDEFGHIJKL");
for (size_t i = 0; i < v.rows(); i++) {
for (size_t j = 0; j < v.cols(); j++) {
std::cout << v[i][j] << ' ';
}
std::cout << "\n";
}
}

Related

How to define a two dimensional array during run time in Visual Studio C++ 11?

I am trying to compile ORBSLAM2 on Windows with Visual Studio 2015 vc14 x64 compiler. The project was originally developed for GNU GCC. I now have the following issue:
// Compute distances between them
const size_t N = vDescriptors.size();
float aDistances[N][N];
for(size_t i=0;i<N;i++) {
aDistances[i][i]=0;
for(size_t j=i+1;j<N;j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
aDistances[i][j]=distij;
aDistances[j][i]=distij;
}
}
I get the this error while compiling:
C2131 expression did not evaluate to a constant
... on this line of code:
const size_t N = vDescriptors.size();
Subsequently the two dimensional array definition fails too (float Distances[N][N];).
What's the best way to solve this in Visual-C++ ?
UPDATE: Here's the complete function code:
void MapPoint::ComputeDistinctiveDescriptors() {
// Retrieve all observed descriptors
vector<cv::Mat> vDescriptors;
map<KeyFrame*,size_t> observations;
{
unique_lock<mutex> lock1(mMutexFeatures);
if(mbBad)
return;
observations=mObservations;
}
if(observations.empty())
return;
vDescriptors.reserve(observations.size());
for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++) {
KeyFrame* pKF = mit->first;
if(!pKF->isBad())
vDescriptors.push_back(pKF->mDescriptors.row(mit->second));
}
if(vDescriptors.empty())
return;
// Compute distances between them
const size_t N = vDescriptors.size();
float aDistances[N][N];
for(size_t i=0;i<N;i++) {
aDistances[i][i]=0;
for(size_t j=i+1;j<N;j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
aDistances[i][j]=distij;
aDistances[j][i]=distij;
}
}
// Take the descriptor with least median distance to the rest
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++) {
vector<int> vDists(aDistances[i], aDistances[i]+N);
sort(vDists.begin(),vDists.end());
int median = vDists[0.5*(N-1)];
if(median<BestMedian) {
BestMedian = median;
BestIdx = i;
}
}
{
unique_lock<mutex> lock(mMutexFeatures);
mDescriptor = vDescriptors[BestIdx].clone();
}
}
Your Problem
You tried to create a 2D array on the stack (this is not standard C++, even though it might work on some compilers). For this the size needs to be know at compile time, which is not the case as you call size() on an object which likely is not a constexpr.
QUICK FIX
A quick fix that works out of the box is to just allocate the memory on the heap (do not forget to delete array later on) by doing
float** aDistances = new float[N][N];
The deletion can be done in a function which looks like this
template <typename T>
void delete2DArray(T** ptr, size_t NumRows)
{
for (size_t i = 0; i < NumRows; i++)
{
delete[] ptr[i];
}
delete[] ptr;
}
FIX
You will haveto use dynamic memory allocation. For this you can try the following approach by adding a wrapper class around std::vector (this should be possible as you said the scope is very manageable)
template <typename T>
class Array2D
{
public:
Array2D(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), array2d(rows * columns)
{}
T& operator()(size_t row, size_t column)
{
return array2d[row * columns + column];
}
const T& operator()(size_t row, size_t column) const
{
return array2d[row * columns + column];
}
T* getRow(size_t row)
{
return &array2d[row * columns];
}
private:
size_t rows;
size_t columns;
std::vector<T> array2d;
};
Than you have to modify your code like this:
// Compute distances between them
const size_t N = vDescriptors.size();
Array2D<float> aDistances(N,N);
for (size_t i = 0; i < N; i++) {
aDistances(i,i) = 0;
for (size_t j = i + 1; j < N; j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i], vDescriptors[j]);
aDistances(i,j) = distij ;
aDistances(j,i) = distij ;
}
}
As you can see the syntax to access elements has slightly changed [x][y] -> (x,y).
EDIT
As the OP has modified the question, I have noticed that the Distances is used a second time which needs attention as well. For this you will have to add a getColumn method (see above) to the Array2D class. Than you further have to modify
// Take the descriptor with least median distance to the rest
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++) {
vector<int> vDists(aDistances.getRow()[i], aDistances.getRow()[i]+N);
sort(vDists.begin(),vDists.end());
int median = vDists[0.5*(N-1)];
if(median<BestMedian) {
BestMedian = median;
BestIdx = i;
}
}
NOTE: I am not perfectly sure if I got it right -- maybe you have to get a
columns instead of a rows (too late to think straight). If this is the case you should also change the memory layout of the Array2D class, i.e. sorting the elements differently in the underlaying 1D-Vector.

how to pass a subvector of a 2d vector in a function in c++

void Solution::rotate(vector<vector<int> > &A) {
int n= A.size();
int temp[n];
for(int j=0;j<n;j++)
{
temp[j]=A[n-1][j];
}
for(int i=0;i<n-1;i++)
{
A[n-1][i]=A[n-i-1][n-1];
A[n-i-1][n-1] = A[0][n-i-1];
A[0][n-i-1]=A[i][0];
A[i][0]=temp[i];
//A[i+1][0]=A[n-1][i+1];
}
}
I want to call the function again and pass the subarray of original array with starting point as (1,1) of the array and the end point as (n-2,n-2) of the array.
Is it possible to get it done without creating a new vector, i mean just by passing some pointer to the function?
If you just want to look at the submatrix or edit a bounded region in place, make a viewer. The viewer doesn't do anything but restrict the the area of the matrix you are allowed to look at. There is no copying and little extra memory used. This is great if you have, for example, a huge picture and you want to view and manipulate 8x8 element areas.
If you need a new matrix of the given view, teach the viewer to create a new matrix based on the view. There is copying involved in this case, but when you want a copy, copying's hard to avoid.
To demonstrate, first I'm going to wander off the beaten path a bit. If you want this to be fast (and who doesn't want fast?) don't use vector<vector>. A vector is guaranteed to be contiguous in memory, but when you have vectors of vectors that guarantee goes out the window and this leads to poor spatial locality and typically to poor cache usage.
Here is a simple example of a Matrix class that is a bit easier to work with and is all one memory chunk so it tends to be more cache friendly.
// wrapping class for 2D matrixes
class Matrix
{
private:
size_t rows, columns; // large, unsigned datatype. Don't want negative
// indices, so why allow them?
std::vector<int> matrix; // 1D vector. Simple and easy to handle.
// also often much faster than vector of vectors
// due to improved spatial locality helping
// predictability of data access
public:
// build zero-filled Matrix
Matrix(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), matrix(rows * columns)
{
}
// 2D to 1D mapping accessor
int & operator()(size_t row, size_t column)
{
// check bounds here
return matrix[row * columns + column];
}
// 2D to 1D mapping accessor for constant Matrix
int operator()(size_t row, size_t column) const
{
// check bounds here
return matrix[row * columns + column];
}
// dimension accessors
size_t getRows() const
{
return rows;
}
size_t getColumns() const
{
return columns;
}
};
Now that we have a faster, nicely contained Matrix class we can make a really simple MatrixView class.
class MatrixView
{
size_t mStartRow; // view offset in row
size_t mStartColumn; // view offset in column
size_t mRows; // number of viewed rows
size_t mColumns; // number of viewed columns
Matrix & mMat; // viewed Matrix
public:
// using start and endpoints in this constructor. A more ideologically correct
// constructor would behave the same as the standard library and take offset
// and length as parameters.
MatrixView(size_t startrow,
size_t startcolumn,
size_t endrow,
size_t endcolumn,
Matrix & mat):
mStartRow(startrow),
mStartColumn(startcolumn),
mRows(endrow - startrow),
mColumns(endcolumn - startcolumn),
mMat(mat)
{
//ensure dimensions make sense
if (startrow > endrow ||
startcolumn > endcolumn ||
mRows > mat.getRows() ||
mColumns > mat.getColumns())
{
throw std::runtime_error("Bad MatrixView dimensions");
}
}
int & operator()(size_t row, size_t column)
{
// check bounds here if you want to
// look at the source matrix plus offsets
return mMat(row+mStartRow, column+mStartColumn);
}
// 2D to 1D mapping accessor for constant Matrix
int operator()(size_t row, size_t column) const
{
// check bounds here if you want to
return mMat(row+mStartRow, column+mStartColumn);
}
// dimension accessors
size_t getRows() const
{
return mRows;
}
size_t getColumns() const
{
return mColumns;
}
// build a new Matrix based on this view
Matrix clone()
{
Matrix result(mRows, mColumns);
for (size_t row = 0; row < mRows; ++row)
{
for (size_t col = 0; col < mColumns; ++col)
{
result(row, col) = mMat(row+mStartRow, col+mStartColumn);
}
}
return result;
}
};
And an example of using this sucker:
// stream formatters
std::ostream & operator<<(std::ostream & out, const Matrix & mat)
{
for (size_t row = 0; row < mat.getRows(); ++row)
{
for (size_t col = 0; col < mat.getColumns(); ++col)
{
std::cout << std::setw(5) << mat(row, col);
}
std::cout << '\n';
}
return out;
}
std::ostream & operator<<(std::ostream & out, const MatrixView & mat)
{
for (size_t row = 0; row < mat.getRows(); ++row)
{
for (size_t col = 0; col < mat.getColumns(); ++col)
{
std::cout << std::setw(5) << mat(row, col);
}
std::cout << '\n';
}
return out;
}
int main()
{
Matrix one(6, 6); // make 6x6 matrix
int count = 0;
// set inputs to make errors really stand out
for (size_t row = 0; row < one.getRows(); ++row)
{
for (size_t col = 0; col < one.getColumns(); ++col)
{
one(row, col) = count++;
}
}
// print initial matrix
std::cout << one << '\n';
// make a view of matrix that leaves off the outside.
MatrixView view(1,1,5,5, one);
// print the view
std::cout << view << '\n';
// get a clone of the view we can pass into a function
Matrix clone = view.clone();
// and print the clone
std::cout << clone << '\n';
}

"Splitting" a matrix in constant time

I am trying to implement Strassen's algorithm for matrix multiplication in C++, and I want to find a way to split two matrices into four parts each in constant time. Here is the current way I am doing so:
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
A11[i][j] = a[i][j];
A12[i][j] = a[i][j+n];
A21[i][j] = a[i+n][j];
A22[i][j] = a[i+n][j+n];
B11[i][j] = b[i][j];
B12[i][j] = b[i][j+n];
B21[i][j] = b[i+n][j];
B22[i][j] = b[i+n][j+n];
}
}
This approach is obviously O(n^2), and it adds n^2*log(n) to the runtime, as it is called for each recursive call.
It seems that the way to do this in constant time is to create pointers to the four sub-matrices, rather than copy over the values, but I am having a difficult time figuring out how to create those pointers. Any help would be appreciated.
Don't think of matrices, think of matrix views.
A matrix view has pointer to a buffer of T, a width, a height, an offset, and a stride between columns (or rows).
We can start with an array view type.
template<class T>
struct array_view {
T* b = 0; T* e = 0;
T* begin() const{ return b; }
T* end() const{ return e; }
array_view( T* s, T* f ):b(s), e(f) {}
array_view( T* s, std::size_t l ):array_view(s, s+l) {}
std::size_t size() const { return end()-begin(); }
T& operator[]( std::size_t n ) const { return *(begin()+n); }
array_view slice( std::size_t start, std::size_t length ) const {
start = (std::min)(start, size());
length = (std::min)(size()-start, length);
return {b+start, length};
}
};
Now our matrix view:
temlpate<class T>
struct matrix_view {
std::size_t height, width;
std::size_t offset, stride;
array_view<T> buffer;
// TODO: Ctors
// one from a matrix that has offset and stirde set to 0.
// another that lets you create a sub-matrix
array_view<T> operator[]( std::size_t n ) const {
return buffer.slice( offset+stride*n, width ); // or width, depending on if row or column major
}
};
Now your code does work on matrix_views, not matrices.
You could create a submatrix class that holds the location in the parent matrix of the smaller matrix you want to use. Mostly just what you already have for your Matrix, except you'd need to store starting indexes for the row and columns, then offset your indexing by those offsets. If done right the main/root matrix would be a submatrix with the full matrix as the bounds.

Writting in a std::vector of std::vectors in the first dimension

I have a std::vector of std::vectors and I want to use a for loop to push back one element to each inner vector. The code looks like this, but clearly does not work because you cannot access each of the vectors in that way (matrix[i] =) and line 8 produces a Segmentation Fault .
std::vector<std::vector<float> > matrix;
for (size_t j = 0; j < number_of_columns; ++j) {
vector<float> elements_to_push = compute_elements();
for (size_t i = 0; i < number_of_rows; ++i) {
matrix[i].push_back(elements_to_push[i]);
}
}
So, I would like to write the elements column-wise. Writing row-wise is not an option for me because I need to use some external functions that expect the elements to be in that order.
I think that a solution involves using a vector of pointers (std::vector<float*>) but I would like to know if it is possible to do it using vectors only as this simplifies things.
Also, it would be the best if the solution does not involve C++11 or later functionality because I have to keep backwards compatibility. However, if you have an answer that uses C++11 or later you can still write it for anyone else who might find it useful.
It would be easier if you computed and pushed rows instead of columns. However here is a solution (since you already know the size of matrix):
std::vector<std::vector<float> > matrix(number_of_rows, std::vector<float>(number_of_columns, float()));
for (size_t j = 0; j < number_of_columns; ++j) {
vector<float> elements_to_push = compute_elements();
for (size_t i = 0; i < number_of_rows; ++i) {
matrix[i][j] = elements_to_push[i];
}
}
I recommend creating a wrapper around a single std::vector in row-major configuration to represent your matrix, making it more convenient to work with than a 2D std::vector. The following should be compatible with pre-c++11 which is why I haven't used auto and some other c++11 onwards features...
template<typename Ty>
class matrix {
// enables use of [][] on matrix objects
class proxy_row_vector {
public:
proxy_row_vector(std::vector<Ty>& _vec, std::size_t cols, std::size_t row_ind)
: vec(_vec), columns(cols), row_index(row_ind) {}
const Ty& operator[](std::size_t col_ind) const {
return vec[row_index*columns + col_ind];
}
Ty& operator[](std::size_t col_ind) {
return vec[row_index*columns + col_ind];
}
private:
std::vector<Ty>& vec;
std::size_t row_index;
std::size_t columns;
};
public:
// construct rows*cols matrix with default-inserted Ty instances
explicit matrix(std::size_t rows, std::size_t cols)
: mtx(rows*cols), rows_(rows), cols_(cols) {}
std::size_t rows() const { return rows_; }
std::size_t columns() const { return cols_; }
// used for const [][] access
proxy_row_vector operator[](std::size_t row_ind) const {
return proxy_row_vector(mtx, cols_, row_ind);
}
// used for mutable [][] access
proxy_row_vector operator[](std::size_t row_ind) {
return proxy_row_vector(mtx, cols_, row_ind);
}
// insert a new row at the end
void push_row(const std::vector<Ty>& row_vec) {
for (std::vector<Ty>::iterator it = row_vec.begin(); it < row_vec.end(); ++it)
mtx.push_back(*it);
++rows_;
}
// insert a new column at the end
void push_column(const std::vector<Ty>& col_vec) {
insert_column(cols_, col_vec);
}
// insert a row at indicated position
void insert_row(size_type row_pos, const std::vector<Ty>& row_vec) {
mtx.insert(mtx.begin() + row_pos*cols_, row_vec.begin(), row_vec.end());
++rows_;
}
// insert a column at indicated position
void insert_column(size_type col_pos, const std::vector<Ty>& col_vec) {
for (std::size_t i = 0; i < col_vec.size(); ++i) {
mtx.insert(mtx.begin() + i*(cols_+1)+col_pos,col_vec[i]);
}
++cols_;
}
private:
std::vector<Ty> mtx;
std::size_t rows_;
std::size_t cols_;
};
Then pushing a new column is simple, using your example:
matrix<float> mat;
std::vector<float> column_to_push = compute_elements();
mat.push_column(column_to_push);
Note: In the matrix class above there is no bounds or size checking as it is a minimal example of such a class. You should add size checking in the row/column inserting methods to avoid trying to push a row vector or column vector which exceeds (or falls short of) the current number of columns or rows of the matrix respectively. Additionally you would probably want to add iterator support (trivial via std::vector iterators) and other methods (e.g. erasing rows/columns).

How do you dynamically allocate a matrix?

How do you dynamically allocate a 2D matrix in C++?
I have tried based on what I already know:
#include <iostream>
int main(){
int rows;
int cols;
int * arr;
arr = new int[rows][cols];
}
It works for one parameter, but now for two. What should I do?
A matrix is actually can be represented as an array of arrays.
int rows = ..., cols = ...;
int** matrix = new int*[rows];
for (int i = 0; i < rows; ++i)
matrix[i] = new int[cols];
Of course, to delete the matrix, you should do the following:
for (int i = 0; i < rows; ++i)
delete [] matrix[i];
delete [] matrix;
I have just figured out another possibility:
int rows = ..., cols = ...;
int** matrix = new int*[rows];
if (rows)
{
matrix[0] = new int[rows * cols];
for (int i = 1; i < rows; ++i)
matrix[i] = matrix[0] + i * cols;
}
Freeing this array is easier:
if (rows) delete [] matrix[0];
delete [] matrix;
This solution has the advantage of allocating a single big block of memory for all the elements, instead of several little chunks. The first solution I posted is a better example of the arrays of arrays concept, though.
You can also use std::vectors for achieving this:
using: 'std::vector< std::vector >'
Example:
#include <vector>
std::vector< std::vector<int> > a;
//m * n is the size of the matrix
int m = 2, n = 4;
//Grow rows by m
a.resize(m);
for(int i = 0 ; i < m ; ++i)
{
//Grow Columns by n
a[i].resize(n);
}
//Now you have matrix m*n with default values
//you can use the Matrix, now
a[1][0]=1;
a[1][1]=2;
a[1][2]=3;
a[1][3]=4;
//OR
for(i = 0 ; i < m ; ++i)
{
for(int j = 0 ; j < n ; ++j)
{ //modify matrix
int x = a[i][j];
}
}
Try boost::multi_array
#include <boost/multi_array.hpp>
int main(){
int rows;
int cols;
boost::multi_array<int, 2> arr(boost::extents[rows][cols] ;
}
arr = new int[cols*rows];
If you either don't mind syntax
arr[row * cols + col] = Aij;
or use operator[] overaloading somewhere. This may be more cache-friendly than array of arrays, or may be not, more probably you shouldn't care about it. I just want to point out that a) array of arrays is not only solution, b) some operations are more easier to implement if matrix located in one block of memory. E.g.
for(int i=0;i < rows*cols;++i)
matrix[i]=someOtherMatrix[i];
one line shorter than
for(int r=0;i < rows;++r)
for(int c=0;i < cols;++s)
matrix[r][c]=someOtherMatrix[r][c];
though adding rows to such matrix is more painful
const int nRows = 20;
const int nCols = 10;
int (*name)[nCols] = new int[nRows][nCols];
std::memset(name, 0, sizeof(int) * nRows * nCols); //row major contiguous memory
name[0][0] = 1; //first element
name[nRows-1][nCols-1] = 1; //last element
delete[] name;
#include <iostream>
int main(){
int rows=4;
int cols=4;
int **arr;
arr = new int*[rows];
for(int i=0;i<rows;i++){
arr[i]=new int[cols];
}
// statements
for(int i=0;i<rows;i++){
delete []arr[i];
}
delete []arr;
return 0;
}
or you can just allocate a 1D array but reference elements in a 2D fashion:
to address row 2, column 3 (top left corner is row 0, column 0):
arr[2 * MATRIX_WIDTH + 3]
where MATRIX_WIDTH is the number of elements in a row.
Here is the most clear & intuitive way i know to allocate a dynamic 2d array in C++. Templated in this example covers all cases.
template<typename T> T** matrixAllocate(int rows, int cols, T **M)
{
M = new T*[rows];
for (int i = 0; i < rows; i++){
M[i] = new T[cols];
}
return M;
}
...
int main()
{
...
int** M1 = matrixAllocate<int>(rows, cols, M1);
double** M2 = matrixAllocate(rows, cols, M2);
...
}
The other answer describing arrays of arrays are correct.
BUT if you are planning of doing a anything mathematical with the arrays - or need something special like sparse matrices you should look at one of the many maths libs like TNT before re-inventing too many wheels
I have this grid class that can be used as a simple matrix if you don't need any mathematical operators.
/**
* Represents a grid of values.
* Indices are zero-based.
*/
template<class T>
class GenericGrid
{
public:
GenericGrid(size_t numRows, size_t numColumns);
GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue);
const T & get(size_t row, size_t col) const;
T & get(size_t row, size_t col);
void set(size_t row, size_t col, const T & inT);
size_t numRows() const;
size_t numColumns() const;
private:
size_t mNumRows;
size_t mNumColumns;
std::vector<T> mData;
};
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns);
}
template<class T>
GenericGrid<T>::GenericGrid(size_t numRows, size_t numColumns, const T & inInitialValue):
mNumRows(numRows),
mNumColumns(numColumns)
{
mData.resize(numRows*numColumns, inInitialValue);
}
template<class T>
const T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx) const
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
T & GenericGrid<T>::get(size_t rowIdx, size_t colIdx)
{
return mData[rowIdx*mNumColumns + colIdx];
}
template<class T>
void GenericGrid<T>::set(size_t rowIdx, size_t colIdx, const T & inT)
{
mData[rowIdx*mNumColumns + colIdx] = inT;
}
template<class T>
size_t GenericGrid<T>::numRows() const
{
return mNumRows;
}
template<class T>
size_t GenericGrid<T>::numColumns() const
{
return mNumColumns;
}
Using the double-pointer is by far the best compromise between execution speed/optimisation and legibility. Using a single array to store matrix' contents is actually what a double-pointer does.
I have successfully used the following templated creator function (yes, I know I use old C-style pointer referencing, but it does make code more clear on the calling side with regards to changing parameters - something I like about pointers which is not possible with references. You will see what I mean):
///
/// Matrix Allocator Utility
/// #param pppArray Pointer to the double-pointer where the matrix should be allocated.
/// #param iRows Number of rows.
/// #param iColumns Number of columns.
/// #return Successful allocation returns true, else false.
template <typename T>
bool NewMatrix(T*** pppArray,
size_t iRows,
size_t iColumns)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{ // I prefer using the shorter 0 in stead of NULL.
if (!((*pppArray) != 0)) // Test if the first element is currently unassigned.
{ // The "double-not" evaluates a little quicker in general.
// Allocate and assign pointer array.
(*pppArray) = new T* [iRows];
if ((*pppArray) != 0) // Test if pointer-array allocation was successful.
{
// Allocate and assign common data storage array.
(*pppArray)[0] = new T [iRows * iColumns];
if ((*pppArray)[0] != 0) // Test if data array allocation was successful.
{
// Using pointer arithmetic requires the least overhead. There is no
// expensive repeated multiplication involved and very little additional
// memory is used for temporary variables.
T** l_ppRow = (*pppArray);
T* l_pRowFirstElement = l_ppRow[0];
for (size_t l_iRow = 1; l_iRow < iRows; l_iRow++)
{
l_ppRow++;
l_pRowFirstElement += iColumns;
l_ppRow[0] = l_pRowFirstElement;
}
l_bResult = true;
}
}
}
}
}
To de-allocate the memory created using the abovementioned utility, one simply has to de-allocate in reverse.
///
/// Matrix De-Allocator Utility
/// #param pppArray Pointer to the double-pointer where the matrix should be de-allocated.
/// #return Successful de-allocation returns true, else false.
template <typename T>
bool DeleteMatrix(T*** pppArray)
{
bool l_bResult = false;
if (pppArray != 0) // Test if pointer holds a valid address.
{
if ((*pppArray) != 0) // Test if pointer array was assigned.
{
if ((*pppArray)[0] != 0) // Test if data array was assigned.
{
// De-allocate common storage array.
delete [] (*pppArray)[0];
}
}
// De-allocate pointer array.
delete [] (*pppArray);
(*pppArray) = 0;
l_bResult = true;
}
}
}
To use these abovementioned template functions is then very easy (e.g.):
.
.
.
double l_ppMatrix = 0;
NewMatrix(&l_ppMatrix, 3, 3); // Create a 3 x 3 Matrix and store it in l_ppMatrix.
.
.
.
DeleteMatrix(&l_ppMatrix);