Matrix class

Pages: 12
do as simple as possible when you code

instead of this ;
1
2
3
bool operator!=(const Matrix<T, ROWS, COLS>& cmp) const {
         return ((*this) == (cmp)) ? false : true;
     }


1
2
3
bool operator!=(const Matrix<T, ROWS, COLS>& cmp) const {
         return !(*this == cmp) ;
     }


all your overloaded operator(+,-,*) are changing the value of this elements
example

1
2
3
Matrix<T, ROWS, COLS> operator*(const T& a) const {
         return Matrix<T, ROWS, COLS > (*this).operator*=(a);
     }




istead a possible solution
1
2
3
4
Matrix<T, ROWS, COLS> operator*(const T& a) const {
         Matrix<T, ROWS, COLS > tmp(*this);
      return tmp *= a;
     }
Last edited on
I prefer using Matrices of variable sizes.
I have a method like this:

 
  void Resize (int r, int c, bool PreserveOldValues=true, const T& TheZero=0);


To me it is quite important to allow passing a reference to the zero object, in case you want to make Matrices of objects whose Zero element is not known in compile time. For example, you might want to make a matrix of Matrices. In this case, if you use variable # of columns& rows, the Zero matrix is not known at compile time - it will have a variable number of rows and columns.
[Edit:] On the first post I misread therockon7throw's suggestion.
His suggestion is the best way to solve the problem. It calls a theoretically non-necessary copy constructor; this is a well-known issue with operator overloading in C++; as far as I know, there is no workaround for it in the current C++ standard (is it going to be fixed in the new coming standard?).

@therockon7throw
Returning a reference to an object allocated on the stack is a very bad idea; it will introduce very-hard to catch bugs.

Matrix<T, COLS, ROWS> Matrix<T, ROWS, COLS>::operator~()
Maybe the return type as reference is an error.


At the very least it is a very bad design decision. Users of operator~ would have to delete the matrix you created for them manually. This is 1) counter-intuitive 2) you will certainly forget to do it at least once 3) every user other than yourself will fail to do it 4) any failure to release your memory will introduce a memory leak, which might stay in your code for years without being caught.


Last edited on
@ne555

I was thinking about my assign operator:

1
2
3
4
5
6
7
template<typename T, int ROWS, int COLS>
Matrix<T, ROWS, COLS>& Matrix<T, ROWS, COLS>::operator=(const Matrix<T, ROWS, COLS>& cp) {
    _elements.clear();
    for (int i = 0; i < cp._cols * cp._rows; i++)
        _elements.push_back(cp(i));
    return *this;
}


You said I don't need this operator and neither to do _elements.clear();
I think you was thinking with _elements = cp._elements;

In this way is true, I don't need to clear because it's implicit. But note that _elements is private so I can't do it.
Then, I think it's necessary to clear it. Am I wrong?
@therockon7throw

all your overloaded operator(+,-,*) are changing the value of this elements
example
...


I think I'm not changing the value of the own object.

I tried:
1
2
3
4
5
Matrix<double, 4, 2 > m(1.1);
std::cout << m;

m*2; //if I undestood well, this may change the value of m
std::cout << m;


The second output are 1.1's.

Did you mean this?
@Aikon

Ok sorry I misread your code

return Matrix<T, ROWS, COLS > (*this).operator*=(a);

the code above should first create a new object by using the copy constructor of your class and than apply the operator *= on the new created object, and finally return the result.

So you are right your code is not changing the current object, this
Last edited on
deleted
Last edited on
@tition

It calls a theoretically non-necessary copy constructor; this is a well-known issue with operator overloading in C++; as far as I know, there is no workaround for it in the current C++ standard (is it going to be fixed in the new coming standard?).


There is a smart way to solve the problem and to eliminate creating and destroying the temporary objects.
It is meta-programming, with C you can write programs, however with C++ you can do a higher degree of prgramming, manipulating programs :-) You can write program thats manipulate code or generates code in compile time, so you are able to avoid creating and destroying temporary objects, which results speed at run time and use of less physical memory.

a simple example may look like following


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

template<class rep >
struct transpose;

template<typename T, int ROWS, int COLS>
class Matrix {
// do some thing

public:
     typedef T value_type;
     typedef  unsigned int size_type;

//do some other things

// you should also implement a copy constructor for the same type
 Matrix<T, ROWS, COLS >& operator=(const transpose< Matrix<T, ROWS, COLS > >& o)
        {
        	  for(unsigned  i = 0; i < _rows; i++)
        	         for (unsigned j = 0; j < _cols; j++)
        	        	 this->operator()(i,j) = o(i,j);
             	return *this;
         }


// do some other thing

// you may overload operator ! to get transpose of the matrix

 transpose< Matrix<T, ROWS, COLS > > operator!(){
    	 return  transpose< Matrix<T, ROWS, COLS > >(*this);
     }
};




And the fun , your tranpose here :-)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<class rep>
struct transpose{

	typedef typename rep::value_type value_type;
	typedef typename rep::size_type size_type;

	transpose(const rep& m):m(m){}
	value_type operator()(int i , int j)const{
		return m(j , i );
	}

	size_type size()const{ return m.size() ;}
// you may also define getCol and getRow

        size_type getCol()const{ return m._cols ;}
        size_type getRow()const{ return m._rows ;}
private:
	const rep& m;

};


hope it helps
Last edited on
You said I don't need this (assigment) operator and neither to do _elements.clear();
I think you was thinking with _elements = cp._elements;

In this way is true, I don't need to clear because it's implicit. But note that _elements is private so I can't do it.
¿Have you tried it?
In c++ you can touch private members from:
_ Yourself
_ Your friends
_ Your same kind

The copy will be simply elements = b.elements;, but the default assignment operator already does that.
However, just notice that you've got const unsigned _rows, _cols; (that will break it as they are not assignable). Get rid of those variables, you don't need them. That info is stored in the template parameters.


return Matrix<T, ROWS, COLS > (*this).operator*=(a); looks obfuscated

By the way, it is not required for vector::clear() to deallocate the memory.
I've got lost. ¿what non-necessary copy constructor call?
deleted
Last edited on
@ne555

The copy will be simply elements = b.elements;, but the default assignment operator already does that.


You are totally right, elements is type of vector, so you dont have to worry about how they are copied, just leave it to the vector his self. vector must care how he copies or assigns his objects :-)

@ Aikon
So you dont need any copy or assignment for the object of your class itself, as ne555 said the default ones do their jobs well.
Last edited on
@neo555

In c++ you can touch private members from:
_ Yourself
_ Your friends
_ Your same kind


Thanks for this, I didn't know it (I had the idea it was like Java). Now I undestand many things.
Sorry, I'm a being such a pain in the neck.

So then I don't need a destructor, do it? The default destructor of vector will be call.

And another question. I already deleted the const int sizes and I was thinking if the templates can deduce the templates themself.

Like:

1
2
 Matrix<int, 2, 2> intMatrix;
Matrix<int> copy = intMatrix;



Another one, lol.
My default constructor is:

1
2
3
template<typename T, int ROWS, int COLS>
Matrix<T, ROWS, COLS>::Matrix()
: _elements(ROWS*COLS, T(0.0)) {


Can it take me problems the T(0.0) with matrices of any object? If so, what is the better solucion?

Thank you very much all of you.
@therockon7throw

I think I almost understood your suggestion: you eliminate the unnecessary copying by using the mechanics of copy constructors and smart templating. This is very smart, however it is also very complicated (on the edge of my understanding).

I prefer waiting for a change in the standard to allow a simpler solution, rather than use your smart trick. In the meantime, if I am pressed for speed (which, in fact, I often am), I will just avoid the use of operator+ and use instead operator+= and thus micro-manage the copy constructors by hand.
c++98
1
2
3
4
T foo();
T bar = foo(); //RVO no copies made

foo().swap( bar ); //swap can be very cheap 


In c++0b there is T&& It seems to be used to implement move assignment and copy constructor.
But I haven't played with it.

@Aikon: _elements(ROWS*COLS)
This may be a little late, but take a look at std::valarray
Last edited on
@tition

I prefer waiting for a change in the standard to allow a simpler solution, rather than use your smart trick. In the meantime, if I am pressed for speed (which, in fact, I often am), I will just avoid the use of operator+ and use instead operator+= and thus micro-manage the copy constructors by hand.


You do not need to wait for the standard, they may never change it the way you expect them to.
you can overload all operator( + , - , *, / ++, -- or whatever else) by using expression template the smartest solution to eliminate temporary objects and to speed up your application in run time. It may have some compile time penatly, but the prise is worth :-)
Last edited on
@therockon7throw

By the way, I loved you example of meta-programming, I will investigate about it and I'll try to write some posts in my blog.

I'm really thankful.
Topic archived. No new replies allowed.
Pages: 12