1) Intanto osserva queste righe del main:
matrixType<int> mat1(2,3),mat2;
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
{
mat1(i,j) = 0;
mat2(i,j) = 0;
}
mat1 ha dimensione 2 x 3, mat2 (visto che usi parametri di default, a mio avviso una pessima idea) ha dimensione 3 x 3. I cicli for iterano per 9 volte in totale quindi sforano la dimensione di mat1 con crash randomici. Già questo è un errore.
2) Non capisco perché il costruttore di default abbia valori di default row = 3, col = 3: una matrice 2 x 2 o 3 x 17 non ha pari dignità forse? Ma soprattutto è una cosa inutile perché se mat2 la usi come risultato di un assegnamento:
a) allochi la memoria per niente
b) perdi il riferimento a tale zona di memoria.
Più sensato sarebbe che il costruttore di default imposti a 0 sia row sia col e a nullptr (visto che usi la versione 4.7 inizia a vedere i costrutti C++11) il puntatore mat.
Per ridimensionare la matrice sarà sufficiente un metodo resize(row,col) per la costruzione a posteriori della matrice.
3) Costruttore copia e operatore assegnamento.
Dato che utilizzi un array per simulare la matrice medianto calcolo di indici (la cosa più efficiente per una classe matrice), il doppio for si può evitare copiando i due array come se fossero array, appunto. Dato che la classe è un template (e che quindi può essere istanziata anche con classi) la cosa migliore da fare è usare
std::copy
std::copy(othermat.mat, othermat.mat + ( row * col ), mat);
sarà poi il compilatore a richiamare una eventuale memcpy per i tipi base (i POD).
4) L'implementazione degli operatori è sbagliata.
template<class elemType>
matrixType<elemType> matrixType<elemType>::operator+(const matrixType<elemType>& othermat) const
{
matrixType<elemType> temp;
assert(row==othermat.row && col==othermat.col);
temp.row = row;
temp.col = col;
Dichiari una matrice temp (per default 3 x 3), fai gli opportuni controlli su row e col e poi assegni tali valori a temp col rischio di falsare i valori interni e il range massimo di temp.mat.
Corretto è:
assert(row==othermat.row && col==othermat.col);
matrixType<elemType> temp(row,col);
for(int i=0; i<row; i++)
for(int j=0; j<col; j++)
temp(i,j) = mat[col*i+j]+othermat(i,j);
return temp;
In questo modo prima controlli che i vincoli siano rispettati e poi ti costruisci la matrice con i valori corretti. Vale anche per gli altri operatori ovviamente.
5) operatore di assegnamento.
A differenza del costruttore di copia, l'operatore di assegnamento lavora su un oggetto fatto e finito. La tua implementazione è quasi corretta perché non tiene conto del fatto che hai già un this->mat allocato. In definitiva hai un memory leak.
Corretto è:
if(this != &othermat)
{
row = othermat.row;
col = othermat.col;
// new potenzialmente lancia un'eccezione.
elementType* tmp = new elemType [row*col];
std::copy(othermat.mat, othermat.mat + ( row * col ), tmp);
delete[] mat;
mat = tmp;
}
return *this;
Il perché lo puoi trovare qui al paragrafo "Eccezioni e self assigment":
http://www.eptacom.net/pubblicazioni/pub_it/ptt.htm
6) Costruttore di spostamento e operatore di spostamento.
Per ovviare all'inconveniente di produrre copie temporanee, il C++11 ha introdotto la move semantics. Questo si traduce nell'implementazione dei costrutti al punto 6.
Te li scrivo qui:
template<class elemType>
matrixType<elemType>::matrixType(matrixType<elemType>&& othermat) :
row(othermat.row), col(othermat.row), mat(othermat.mat)
{
othermat.row = 0;
othermat.col = 0;
mat = nullptr;
}
template <class elemType>
matrixType<elemType>& matrixType<elemType>::operator=(matrixType<elemType>&& othermat)
{
if(this != &othermat)
{
row = othermat.row;
col = othermat.col;
mat = othermat.mat;
othermat.row=0;
othermat.col=0;
othermat.mat=nullptr;
}
return *this;
}
Nota che in questo caso, non viene copiato mat, ma viene "rubato" a othermat. Il che si traduce in un aumento delle prestazioni. Il compilatore (automaticamente) userà questi costrutti durante le restituzioni di matrici dopo le varie operazioni.
(Ad esempio prova a scrivere una funzione che accetti una matrice per copia e vedi che succede col debugger).