I have a simple class, whose index operator I've overloaded:
class dgrid{
double* data; // 1D Array holds 2D data in row-major format
public:
const int nx;
const int ny;
double* operator[] (const int index) {return &(data[index*nx]);}
}
This way dgrid[x][y] works as a 2d array, but the data is contiguous in memory.
However, from inside member functions this is a little more clunky, I need to do something like (*this)[x][y] which works, but seems smelly, especially when I have sections like:
(*this)[i][j] = (*this)[i+1][j]
+ (*this)[i-1][j]
+ (*this)[i][j+1]
+ (*this)[i][j-1]
- 4*(*this)[i][j];
Is there a better way to do this? Something like this->[x][y] (but this doesn't work). Is using a little function f(x,y) returns &data[index*nx+ny] the only option?
You could overload ->, but why not simply do:
T& that = *this; //or use auto as t.c. suggests
that[i][j] = that[i+1][j]
+ that[i-1][j]
+ that[i][j+1]
+ that[i][j-1]
- 4*that[i][j];
That's (pun) at least as readable as this->[][]. No ?
Related
I have created a one dimensional vector of int, how may I treat it like 2 dimensional one?
While I can write arr[1]; I can't write arr[1][2];
Why I need this:
Instead of defining a vector of vectors [3x5] I defined a vector whose length is 15, so every time I have a function that takes coordinations of a place in matrix I have to call another function which converts those into one dimensional value, which is really annoying.
Assuming you want to treat a 1D array of size N as a 2D array with M columns, then you can write a helper function that computes the 1D index given 2D indexes:
auto in = [M] (int i, int j) { return i * M + j; };
and then use it like this:
arr[in(i,j)];
This is at least preferable to saying arr[i * M + j] everywhere, which is error prone.
Ideally, you would wrap this 1D array into a class that supports 2D indexing.
It seems to me that the best solution is avoid at all the double operator[] and define an at() function that receive two indexes.
Anyway, if you really (really!) want a double operator[] solution, the first one has to return an object with requested data and support the second operator[]
I propose the following skeletal example, where a arr2d (with compile time known dimension) is based over a mono-dimensional std::array.
#include <array>
#include <iostream>
template <typename T, std::size_t Dim1, std::size_t Dim2>
class Arr2d
{
private:
using int_arr_t = std::array<T, Dim1 * Dim2>;
int_arr_t arr{};
public:
struct foo
{
int_arr_t & arr;
std::size_t const i1;
T & operator[] (std::size_t i2)
{ return arr[i1*Dim1 + i2]; }
T const & operator[] (std::size_t i2) const
{ return arr[i1*Dim1 + i2]; }
};
foo operator[] (std::size_t i1)
{ return {arr, i1}; }
foo const operator[] (std::size_t i1) const
{ return {arr, i1}; }
};
int main ()
{
Arr2d<int, 2, 3> a2d;
a2d[1][2] = 3;
std::cout << a2d[1][2] << std::endl;
}
As you can see, the arr2d::operator[] return a foo object containing a reference to the std::array and the first index.
The foo::operator[] complete the job, returning a reference (or a constant reference, according the case) to the right element inside the original std::array.
But, I repepeat: i prefer a couple of at() functions in Arr2d
T & at (std::size_t i1, std::size_t i2)
{ return arr[i1*Dim1 + i2]; }
T const & at (std::size_t i1, std::size_t i2) const
{ return arr[i1*Dim1 + i2]; }
The use of the comma operator was deprecated inside square brackets with C++20. This will in the future enable to write something like m[i, j] for matrix access.
Until then your only chance is to use a member function like at.
A clever and not recommended approach is to have operator[] return some kind of row proxy that has a operator[] on its own to perform the indexing. That is shown here.
Note that storing the row_proxy can lead to dangling pointers which is why operator[]is only implemented for rvalue references.
I am using trying to solve the Shortest Path problem in C++. For that I have created the following Graph() constructor.
Graph::Graph(int NumberOfVertices){
this->NumberOfVertices=NumberOfVertices;
cout<<"Graph()"<<endl;
//declaring the weight matrix
WeightMatrix=new int*[NumberOfVertices];
for(int a=0;a<NumberOfVertices;a++)
WeightMatrix[a]=new int[NumberOfVertices];
//initialising the weight matrix
WeightMatrix[NumberOfVertices][NumberOfVertices]={0};
ShortestPathArray=new int[NumberOfVertices];
}
I have two questions.
Why is a simple declaration like
WeightMatrix=new int[NumberOfVertices][NumberOfVertices] not allowed? I tried doing so but there were errors. I found the solution online, but am not able to understand it.
The initialization step is not working. The code doesn't proceed further than this statement WeightMatrix[NumberOfVertices][NumberOfVertices]={0};
When I comment out this step everything works fine.
Question #1:
The type of WeightMatrix is int**, so you cannot initialize it with new int[...].
As you seem to have already fixed in your code, the right way is to initialize it with new int*[...].
Question #2:
Initializing an array to a list of values is allowed only at declaration. For example:
int WeightMatrix[M][N] =
{
{1,2,3,...},
{4,5,6,...},
...
};
So you can fix the compilation error by changing this:
WeightMatrix[NumberOfVertices][NumberOfVertices]={0};
To this:
for (int i=0; i<NumberOfVertices; i++)
for (int j=0; j<NumberOfVertices; j++)
WeightMatrix[i][j] = 0;
Why is a simple declaration like WeightMatrix=new int[NumberOfVertices][NumberOfVertices] not allowed? I tried doing so but there were errors. I found the solution online, but am not able to understand it.
It should help to compare this to creation of an array on the stack, for which you can do:
int my_array[X][Y];
When you later say my_array[x][y], the compiler's record of the value Y is used to find the int value at address &my_array + x * Y + y. But, when you use new and specify a dimension at run-time, the compiler isn't obliged to store the dimension(s) involved - that would adversely affect run-time memory usage and performance. Without such dimensions though, the compiler can't support a [x][y] notation, so it's misleading to let you use new as if it were creating a multi-dimensional array. In practice, implementations sometimes store the single allowed array dimension in some extra memory they ask for when you use new[] so they can iterate over the right number of elements to call destructors, but they might want to avoid that for types such as int that require no destruction.
The expectation is that you'll work out the total number of elements you need:
int* weightMatrix = new int[NumberOfVertices * NumberOfVertices];
Then what's conceptually weightMatrix[x][y] can be stored at weightMatrix[x * NumberOfVertices + y] (or if you prefer weightMatrix[x + NumberOfVertices * y]).
I recommend writing a simple class that has an operator to provide a convenient notation ala matrix(x, y):
template <typename T>
class Matrix
{
Matrix(size_t X, size_t Y = X) : X_(X), Y_(Y), p_(new T[X * Y]) { }
~Matrix() { delete[] p_; }
T& operator()(size_t x, size_t y) { return p_[x * Y + y]; }
const T& operator()(size_t x, size_t y) const { return p_[x * Y + y]; }
size_t X_, Y_;
T* p_;
};
Then you can write simpler, cleaner and more robust client code:
Matrix matrix(20, 10);
matrix(4, 2) = 13;
You can also easily put checks in operator() to catch out-of-bound indexing during development and testing.
I wrote an IntegerMatrix class to add my own methods to work with matrices. Now I've written a function like this:
IntegerMatrix** IntegerMatrix::multiplyMatrix(IntegerMatrix** table2)
(It's a double pointer because I'm holding a huge array of pointers to 4x4 2D arrays.) so I simply could do this:
matrix1.multplyMatrix(matrix2)
One little problem is the * isn't defined for my own class. So I thought to overload this operator that I could do something like this:
sum += this->table[i][k] * table2[k][j];
But how can I get the right i and k in the overloaded operator, which is defined like this:
IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & k);
The only problem I can't figure out right now is how to get the right values ?
EDIT:
I've rewrote this and now I have:
IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & table2)
{
int i, j, k;
int sum;
IntegerMatrix * result = new IntegerMatrix(SIZE);
for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++) {
sum = 0;
for (k = 0; k < SIZE; k++) {
sum += this->table[i][k] * table2[k][j];
}
result[i][j] = sum;
}
}
return *result;
}
That gives me just an error on the [] :
Binary '[' : 'IntegerMatrix' does not define this operator or a conversiont o a type acceptable to the predefined operator.
I don't understand your question, but here's a brief demo of how matrix multiplication normall works:
class IntegerMatrix {
int table[3][3];
public:
IntegerMatrix& operator*=(const IntegerMatrix& rhs) {
//multiply table by rhs.table, store in data.
return *this;
}
};
IntegerMatrix operator*(IntegerMatrix lhs, const IntegerMatrix& rhs)
{return lhs*=rhs;} //lhs is a copy, so we can alter and return it
FOR YOUR EDIT
You have the code
IntegerMatrix * result = new IntegerMatrix(SIZE); //pointer to an IntegerMatrix
...
result[i][j] = sum; //assign sum to the jth index of matrix # i
when in actuality, I presume you wanted
result->table[i][j] = sum; //sum to the ixj index of the result matrix.
Also, your function is leaky, because you have a new, but no delete. This is easy to fix in your case, since you don't need the new. (Are you from a Java or C# background?)
IntegerMatrix result(SIZE);
...
result[i][j] = sum;
...
return result;
Unrelated to all of the above, you might actually want to provide a [] operator for your Integer Matrix.
class row {
int* data;
int size;
public:
row(int* d, int s) :data(d), size(s) {}
int& operator[](int offset) {
assert(offset<size);
return data[offset];
}
};
row operator[](int column) {
assert(column<SIZE);
return row(table[column], SIZE);
}
And this would allow you to write:
IntegerMatrix result;
result[i][j] = sum;
You may be carrying over some artifacts, in sort of a Cargo-Cult programming sense. :-/
For instance: I'm guessing that the double indirections (**) on your prototype for multiplyMatrix are there because you saw multidimensional arrays of integers around somewhere...stuff like:
void printMatrix(int ** myMatrix, int rows, int columns);
The double-indirection is just a pointer-to-a-pointer. It's a way of achieving the specific implementation point of passing low-level C-style 2D arrays as parameters. But it's not something you have to tack on any time you're working with an abstract class that happens to represent a Matrix. So once you've encapsulated the matrix size and data itself inside the IntegerMatrix class, you don't want something like this:
void printMatrix(IntegerMatrix ** myMatrix);
More likely you'd want to pass in a simple reference to the class which is encapsulating the data, like this:
void printMatrix(IntegerMatrix const & myMatrix);
You should actually return a new matrix from your multiplication function, at least if you're using it to implement an operator overload...because semantically it does not make sense for people to write things like a * b; and have that modify a. (It can, but you shouldn't.) So you are left with either the choice of returning a matrix value instance:
IntegerMatrix IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);
...or returning a pointer to a new object:
IntegerMatrix * IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);
Returning by pointer has historically been chosen by many libraries because returning by value from a local variable in the function would involve making a copy at the time of return. Returning a pointer is fast (it "copies" only one 32-bit/64-bit number) while copying an instance of an object and large blocks of data inside it is slow. So a lot of libraries would just use Matrix pointers everywhere...with the problem that it becomes hard to know whose responsibility it is to ultimately delete the object. Smart pointers are one way of ensuring this:
unique_ptr<IntegerMatrix> IntegerMatrix::multiplyMatrix(IntegerMatrix const & rhs);
But C++11 has some sneaky ability to be just as fast without the mess. If you return something by value from a function and the compiler is sure that value isn't going to be used again (since it's going out of scope), then it can be "moved" about as fast as a pointer could. This requires that you support move construction by RValue reference, and there's all kinds of trickiness in that.
There's really a lot of nuance. If you're doing this as an educational exercise, I'd suggest taking it slowly and going through a tutorial that walks you through every step instead of jumping straight into the fire. And if you're using low-level C arrays and dynamic allocations inside your matrix, change them to a std::vector of std::vector.
For one IntegerMatrix object you're using this->table[i][k] to refer to the array where you're holding the matrix data, while for the table2 object reference and the result pointer, you're using table2[k][j] and result[i][j].
I think that what you want to do is something like:
IntegerMatrix IntegerMatrix::operator*(const IntegerMatrix & table2)
{
int i, j, k;
int sum;
IntegerMatrix * result = new IntegerMatrix(SIZE);
for (i = 0; i < SIZE; i++) {
for (j = 0; j < SIZE; j++) {
sum = 0;
for (k = 0; k < SIZE; k++) {
sum += this->table[i][k] * table2.table[k][j];
}
result->table[i][j] = sum;
}
}
return *result;
}
I have my own mathematical Vector class that I use in my code. I have a new need to generalize my vector class to n dimensions instead of just two.
My question is, what's the best way to implement the operator overloads, and is there a significant overhead to doing this?
I now store the values in an array
double *vals;
....
vals = new double[dimension];
With this, I implement the + operator like so:
Vector Vector::operator+(Vector v)
{
Vector ret = Vector(dimension);
for (int i = 0; i < dimension; i ++)
{
ret.vals[i] = vals[i] + v.vals[i];
}
}
This operation will be done a LOT and has to run fast. Is this significantly worse than the old version (as far as speed)?
Vector Vector::operator+(Vector v) {
return Vector(x + v.x, y + v.y);
}
Thanks for any input!
If you want a fast vector class then use templates for the size:
template<std::size_t size>
class Vector {
double data[size];
public:
double& operator[](std::size_t x) { return data[x]; }
};
template<std::size_t size>
Vector<size> operator+(Vector<size> lhs, const Vector<size>& rhs) {
for (std::size_t i = 0; i < size; ++i)
lhs[i] += rhs[i];
return lhs;
}
Having them be dynamic size is only unnecessary if you want to re-size them, or if they are incredibly large.
There are ways to get much faster than this, such as SSE. You should use a dedicated math library if you want something highly optimized.
First, I would suggest passing your operand by reference instead of by value to avoid an unnecessary object copy:
Vector Vector::operator+(const Vector &v) {
Second, most compilers implement Return Value Optimization which will help eliminate the local ret in your multidimensional implementation.
The best approach, of course, is to implement your code, benchmark it, and then apply optimisations where necessary. Scott Meyers' Effective C++ is an excellent reference for the sort of thing you're attempting to do here.
I was implementing a small dense matrix class and instead of plan get/set operators I wanted to use operator overloading to make the API more usable and coherent.
What I want to achieve is pretty simple:
template<typename T>
class Matrix
{
public:
/* ... Leaving out CTOR and Memory Management for Simplicity */
T operator() (unsigned x, unsigned y){/* ... */ }
};
Matrix<int> m(10,10);
int value = m(5,3); // get the value at index 5,3
m(5,3) = 99; // set the value at index 5,3
While getting the value is straight forward by overloading operator(), I can't get my head around defining the setter. From what I understood the operator precedence would call operator() before the assignment, however it is not possible to overload operator() to return a correct lvalue.
What is the best approach to solve this problem?
I dispute that "it's not possible" to do the correct thing:
struct Matrix
{
int & operator()(size_t i, size_t j) { return data[i * Cols + j]; }
const int & operator()(size_t i, size_t j) const { return data[i * Cols + j]; }
/* ... */
private:
const size_t Rows, Cols;
int data[Rows * Cols]; // not real code!
};
Now you can say, m(2,3) = m(3,2) = -1; etc.
The answer to your question is what Kerrek already stated: you can provide an overload by changing the signature of the operator, which in this case can be achieved by modifying the const-ness of the function.
But I would recommend that you at least consider providing a separate setter for the values. The reason is that once you return references to your internal data structures you loose control of what external code does with your data. It might be ok in this case, but consider that if you decided to add range validation to the implementation (i.e. verify that no value in the matrix is above X or below Y), or wished to optimize some calculation on the matrix (say the sum of all of the elements in the matrix is an often checked value, and you want to optimize away the calculation by pre-caching the value and updating it on each field change) it is much easier to control with a method that receives the value to set.