C++ - Problema con operador delete

Iniciado por xaps, 13 Diciembre 2013, 18:50 PM

0 Miembros y 1 Visitante están viendo este tema.

xaps

Cita de: amchacon en 16 Diciembre 2013, 15:54 PM
Código (cpp) [Seleccionar]
bool operator ==(const Matriz &a, const Matriz &b)
{
if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return false;
for (int i = 0; i < a.nfilas; ++i)
   for (int j = 0; j < a.ncolumnas; ++j)
     if (a.matr[i][j] != b.matr[i][j]) return false;

return true;
}

bool operator !=(const Matriz &a, const Matriz &b)
{
if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return true;
for (int i = 0; i < a.nfilas; ++i)
   for (int j = 0; j < a.ncolumnas; ++j)
     if (a.matr[i][j] != b.matr[i][j]) return true;

return false;
}


Esas líneas se pueden reducir a:

Código (cpp) [Seleccionar]
bool operator ==(const Matriz &a, const Matriz &b)
{
if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return false;
for (int i = 0; i < a.nfilas; ++i)
   for (int j = 0; j < a.ncolumnas; ++j)
     if (a.matr[i][j] != b.matr[i][j]) return false;

return true;
}

bool operator !=(const Matriz &a, const Matriz &b)
{
return !(a == b);
}

Cierto. Aún no estoy muy acostumbrado a reciclar código...  :silbar:

Cita de: amchacon en 16 Diciembre 2013, 15:54 PM
Te falta por añadir los determinantes (para una matriz nxn).
Para cálculo de determinantes el mejor método es Laplace, ¿verdad?

Cita de: amchacon en 16 Diciembre 2013, 15:54 PM
Y los operadores *= y /= (este ultimo con números enteros).
Cierto. Aunque la división no la he implementado por dos razones:
- La primera, nunca he dividido dos matrices. Supongo que no debe usarse demasiado o que no lo he necesitado de momento.
- La segunda, el hecho de que esté trabajando con enteros hace que la mayoría de divisiones sean inválidas.

Debería cambiar el tipo numérico de la matriz a float para poder realizar divisiones, ¿no? Ya que para escalonar y hacer Gauss probablemente necesite dividir según que posiciones de la matriz.
"The programmers of tomorrow are the wizards of the future" - Gave Newel

amchacon

Cita de: xaps en 16 Diciembre 2013, 16:56 PMPara cálculo de determinantes el mejor método es Laplace, ¿verdad?
Es el que uso yo, aunque yo detengo el algoritmo cuando es 2x2.

Cita de: xaps en 16 Diciembre 2013, 16:56 PMCierto. Aunque la división no la he implementado por dos razones:
- La primera, nunca he dividido dos matrices. Supongo que no debe usarse demasiado o que no lo he necesitado de momento.
Dividir 2 matrices es multiplicar por su inversa.

Pero no me refería a eso sino a la división con un entero.

Cita de: xaps en 16 Diciembre 2013, 16:56 PMLa segunda, el hecho de que esté trabajando con enteros hace que la mayoría de divisiones sean inválidas.
Quizás deberías plantearte hacerlo todo a double (o mejor aún, hazlo en formato plantilla y que el usuario decida).
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

xaps

Cita de: amchacon en 16 Diciembre 2013, 17:12 PM
Dividir 2 matrices es multiplicar por su inversa.
Cierto, no se en que estaría pensando.

Cita de: amchacon en 16 Diciembre 2013, 17:12 PM
Quizás deberías plantearte hacerlo todo a double (o mejor aún, hazlo en formato plantilla y que el usuario decida).
Estaba pensando en usar los templates, pero entonces tengo el problema de que a alguien se le ocurra declarar una matriz de un tipo que no sea numérico, como char o alguna clase no genérica. ¿Que se puede hacer en estos casos? He visto que se pueden hacer especializaciones, pero es imposible hacer una especialización para cada tipo de dato que considere no válido para mi matriz :S
"The programmers of tomorrow are the wizards of the future" - Gave Newel

amchacon

Cita de: xaps en 16 Diciembre 2013, 17:29 PMEstaba pensando en usar los templates, pero entonces tengo el problema de que a alguien se le ocurra declarar una matriz de un tipo que no sea numérico, como char
char es un dato número, es como si fuera un int de 1 byte.

Cita de: xaps en 16 Diciembre 2013, 17:29 PMo alguna clase no genérica. ¿Que se puede hacer en estos casos?
No hay ningún problema mientras la clase que use tenga definido los operadores correspondientes (+ - * / ==...).

O al menos tenga definido los operadores de las funciones que vaya a usar.
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

xaps

#24
Cita de: amchacon en 16 Diciembre 2013, 18:07 PM
char es un dato número, es como si fuera un int de 1 byte.
No hay ningún problema mientras la clase que use tenga definido los operadores correspondientes (+ - * / ==...).

O al menos tenga definido los operadores de las funciones que vaya a usar.
Pues me he puesto a estudiar y implementar los templates en la clase, pero me he encontrado con un problema que no me deja avanzar. La mayoría de mis sobrecargas de operadores son funciones amigas de la función, y por lo visto en general hay problemas al implementar los templates con funciones amigas. No sé si por suerte o por desgracia, la única función que parece no encajar bien con los templates es la de sobrecarga del producto. A ver si me podéis ayudar con esto, que llevo un buen rato peleándome con el error buscando, moviendo y cambiando código... Pero no lo consigo.

Vuelvo a pegar el código entero de la clase (ya que se han tenido que cambiar bastantes cosas) y el mensaje de error que estoy recibiendo:

Matriz.h:
Código (cpp) [Seleccionar]
#include <iostream>

using namespace std;

template <class T>
class Matriz {

private:
 
 int nfilas;
 int ncolumnas;
 T **matr = NULL;
 
 void borrar();

public:

 //Constructora
 Matriz(int filas, int columnas);
 
 //Constructora-copiadora
 Matriz(const Matriz<T> &m);
 
 //Destructora
 ~Matriz();
 
 //Consultoras
 int filas() const;
 int columnas() const;
 T consultar(int fila, int columna) const;
 
 //Modificadora
 void modificar(int fila, int columna, T x);
 
 //Operadores
 Matriz& operator =(const Matriz<T> &b);
 
 void operator +=(const Matriz<T> &mat);
 void operator -=(const Matriz<T> &mat);
 
 friend Matriz operator + <>(const Matriz<T> &a, const Matriz<T> &b);
 friend Matriz operator - <>(const Matriz<T> &a, const Matriz<T> &b);
 friend Matriz operator * <>(const Matriz<T> &a, const Matriz<T> &b);
 friend Matriz operator * <>(const Matriz<T> &a, int b);
 friend Matriz operator * <>(int a, const Matriz<T> &b);
 
 friend bool operator == <>(const Matriz<T> &a, const Matriz<T> &b);
 friend bool operator != <>(const Matriz<T> &a, const Matriz<T> &b);
 
 friend ostream& operator << <>(ostream &salida, const Matriz<T> &mat);
 friend istream& operator >> <>(istream &entrada, Matriz<T> &mat);
};

template <class T>
Matriz<T>::Matriz(int filas = 0, int columnas = 0) : nfilas(filas), ncolumnas(columnas)
{
 if (nfilas > 0 and ncolumnas > 0)
 {
   matr = new T* [filas];
   for (int i = 0; i < filas; ++i) matr[i] = new T [columnas];
 }
}

template <class T>
Matriz<T>::Matriz(const Matriz<T> &m) { *this = m; }

template <class T>
Matriz<T>::~Matriz() { borrar(); }

template <class T>
void Matriz<T>::borrar()
{
 if (this->matr != NULL)
 {
   for (int i = 0; i < nfilas; ++i) delete[] matr[i];
   delete[] matr;
   matr = NULL;
 }
}

template <class T>
int Matriz<T>::filas() const { return nfilas;}

template <class T>
int Matriz<T>::columnas() const { return ncolumnas;}

template <class T>
T Matriz<T>::consultar(int fila, int columna) const { return matr[fila][columna];}

template <class T>
void Matriz<T>::modificar(int fila, int columna, T x) { matr[fila][columna] = x;}

template <class T>
Matriz<T>& Matriz<T>::operator =(const Matriz<T> &mat)
{
 if (this != &mat)
 {
   this->borrar();

   if (mat.matr)
   {
     this->nfilas = mat.nfilas;
     this->ncolumnas = mat.ncolumnas;
     
     this->matr = new int* [nfilas];
     for (int i = 0; i < nfilas; ++i)
this->matr[i] = new int [ncolumnas];
     
     for (int i = 0; i < nfilas; ++i)
     {
for (int j = 0; j < ncolumnas; ++j)
 this->matr[i][j] = mat.matr[i][j];
     }
   }
 }
 return *this;
}

template <class T>
void Matriz<T>::operator +=(const Matriz<T> &mat)
{
 if (this->nfilas != 0 and this->ncolumnas != 0 and mat.nfilas != 0 and mat.ncolumnas != 0)
 {
   for (int i = 0; i < nfilas; ++i)
     for (int j = 0; j < ncolumnas; ++j)
this->matr[i][j] += mat.matr[i][j];
 }
}

template <class T>
void Matriz<T>::operator -=(const Matriz<T> &mat)
{
 if (this->nfilas != 0 and this->ncolumnas != 0 and mat.nfilas != 0 and mat.ncolumnas != 0)
 {
   for (int i = 0; i < nfilas; ++i)
     for (int j = 0; j < ncolumnas; ++j)
this->matr[i][j] -= mat.matr[i][j];
 }
}

template <class T>
Matriz<T> operator +(const Matriz<T> &a, const Matriz<T> &b)
{
 int filas = a.nfilas;
 int columnas = a.ncolumnas;
 
 Matriz<T> res(filas, columnas);
 
 for (int i = 0; i < filas; ++i)
   for (int j = 0; j < columnas; ++j)
     res.matr[i][j] = a.matr[i][j] + b.matr[i][j];
   
 return res;
}

template <class T>
Matriz<T> operator -(const Matriz<T> &a, const Matriz<T> &b)
{
 int filas = a.nfilas;
 int columnas = a.ncolumnas;
 
 Matriz<T> res(filas, columnas);
 
 for (int i = 0; i < filas; ++i)
   for (int j = 0; j < columnas; ++j)
     res.matr[i][j] = a.matr[i][j] - b.matr[i][j];
   
 return res;
}

template <class T>
Matriz<T> operator *(const Matriz<T> &a, const Matriz<T> &b)
{
 if (a.ncolumnas == b.nfilas)
 {
   int pos = a.ncolumnas;
   
   int filas = a.nfilas;
   int columnas = b.ncolumnas;
   
   Matriz<T> res(filas, columnas);
   for (int i = 0; i < filas; ++i)
   {
     for (int j = 0; j < columnas; ++j)
     {
int value = 0;
for (int k = 0; k < pos; ++k) value += a.matr[i][k] * b.matr[k][j];
res.matr[i][j] = value;
     }
   }
   return res;
 }
}

template <class T>
Matriz<T> operator *(const Matriz<T> &a, int b)
{
 int filas = a.nfilas;
 int columnas = a.ncolumnas;
 
 Matriz<T> res(filas, columnas);
 for (int i = 0; i < filas; ++i)
   for (int j = 0; j < columnas; ++j) res.matr[i][j] = a.matr[i][j] * b;
 
 return res;
}

template <class T>
Matriz<T> operator *(int a, const Matriz<T> &b) { return b*a; }

template <class T>
bool operator ==(const Matriz<T> &a, const Matriz<T> &b)
{
 if (a.nfilas != b.nfilas or a.ncolumnas != b.ncolumnas) return false;
 for (int i = 0; i < a.nfilas; ++i)
   for (int j = 0; j < a.ncolumnas; ++j)
     if (a.matr[i][j] != b.matr[i][j]) return false;
 
 return true;
}

template <class T>
bool operator !=(const Matriz<T> &a, const Matriz<T> &b) { return !(a == b); }

template <class T>
ostream& operator <<(ostream &salida, const Matriz<T> &mat)
{
 for (int i = 0; i < mat.nfilas; ++i)
 {
   for (int j = 0; j < mat.ncolumnas; ++j) salida << mat.matr[i][j] << " ";
   salida << endl;
 }
 return salida;
}

template <class T>
istream& operator >>(istream &entrada, Matriz<T> &mat)
{
 for (int i = 0; i < mat.nfilas; ++i)
   for (int j = 0; j < mat.ncolumnas; ++j) entrada >> mat.matr[i][j];
 return entrada;
}


Y el error que recibo al compilar la clase es el siguiente:
Matriz.h:43:26: error: declaration of 'operator*' as non-function
Matriz.h:43:26: error: expected ';' at end of member declaration
Matriz.h:43:28: error: expected unqualified-id before '<' token
Matriz.h:44:26: error: declaration of 'operator*' as non-function
Matriz.h:44:26: error: expected ';' at end of member declaration
Matriz.h:44:28: error: expected unqualified-id before '<' token
Matriz.h:45:26: error: declaration of 'operator*' as non-function
Matriz.h:45:26: error: expected ';' at end of member declaration
Matriz.h:45:28: error: expected unqualified-id before '<' token


Como podéis ver he añadido "<>" al final del nombre de cada función amiga de la clase, ya que buscando solución a un problema anterior he visto que la mayoría de códigos implementaban esa metodología para las funciones amigas de la clase. Hay más información sobre ésto aquí: http://c.conclase.net/curso/?cap=040c#042_amigaplantilla
Tampoco descarto que os encontréis alguna que otra barbaridad con los templates :silbar:

Gracias por la ayuda! ^^
"The programmers of tomorrow are the wizards of the future" - Gave Newel

amchacon

La implementación no coindice con la declaración en la clase (Matriz != Matriz<T>).
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

xaps

Cita de: amchacon en 17 Diciembre 2013, 19:37 PM
La implementación no coindice con la declaración en la clase (Matriz != Matriz<T>).
No se a que te refieres exactamente... ¿Dices que en la declaración en la clase de las funciones amigas, he puesto Matriz en vez de Matriz<T>? Aunque lo cambie sigo teniendo el mismo problema :S
Creo que el compilador está dejando de mostrarme errores a partir de que encuentra ese, porque ayer ya estuve corrigiendo varias malas implementaciones del template y el compilador no se quejaba.  :silbar:

De todas formas, hoy le he preguntado a mi profesor de programación de la universidad sobre esto, y me ha dicho que si podía implementarlo como miembro de la clase y aplicarle la etiqueta const hasta ganaría eficiencia, ya que el compilador ya trabajaría de manera distinta que si no fuera una función constante. También me ha dicho que no desarrolla una clase y implementa sobrecargas de operadores y funciones amigas desde hace varios años, por lo que los métodos pueden haber cambiado. ¿Que opináis sobre esto?
"The programmers of tomorrow are the wizards of the future" - Gave Newel

amchacon

Yo lo de operadores "amigos" nunca los he usado, asi que no te puedo ayudar más en eso  :silbar:

Los de los const es bastante importante ahora que lo dices, no solo con los operadores sino con las funciones también.
Por favor, no me manden MP con dudas. Usen el foro, gracias.

¡Visita mi programa estrella!

Rar File Missing: Esteganografía en un Rar

xaps

#28
Pues creo que voy a hacer lo que me ha dicho mi profesor, pondré las sobrecargas como miembros de la clase y aprovecharé para declararlas constantes.

En cuanto tenga una versión presentable la subo para que la veáis ^^

Gracias por la ayuda!

EDITO:

Ya he conseguido implementar la clase con templates. Os añado el código y a continuación os explico un poco que he hecho/modificado para que me funcione.

Matriz.h
Código (cpp) [Seleccionar]
#include <iostream>
 
using namespace std;

/*ostream y iostream no son templates, no entienden los cast dinámicos que se hacen con un template,
*es por esto que se necesita redefinir la clase y el método antes que el template, para convertirlo en template
*http://www.elrincondelc.com/nuevorincon/foros/viewtopic.php?t=13415&view=next&sid=02c39e45352bd867b56de65ebb1afd22
*/
template <class T> class Matriz;
template <class T> ostream& operator <<(ostream &salida, const Matriz<T> &mat);
template <class T> istream& operator >>(istream &entrada, Matriz<T> &mat);
/* --- */

template <class T> class Matriz {
 
private:
 
  int nfilas;
  int ncolumnas;
  T **matr = NULL;
 
  void borrar();
 
public:
 
  //Constructora
  Matriz(int filas, int columnas);
 
  //Constructora-copiadora
  Matriz(const Matriz& m);
 
  //Destructora
  ~Matriz();
 
  //Consultoras
  int filas() const;
  int columnas() const;
  T consultar(int fila, int columna) const;
 
  //Modificadora
  void modificar(int fila, int columna, T x);
 
  //Operadores
  Matriz<T>& operator =(const Matriz &b);
 
  void operator +=(const Matriz &mat);
  void operator -=(const Matriz &mat);
 
  Matriz<T> operator +(const Matriz &b) const;
  Matriz<T> operator -(const Matriz &b) const;
  Matriz<T> operator *(const Matriz &b) const;
 
  Matriz<T> operator *(int b) const;
//Matriz<T> operator *(int a, const Matriz &b); Está declarada como pública y externa a la clase
 
  bool operator ==(const Matriz &b) const;
  bool operator !=(const Matriz &b) const;
 
  friend ostream& operator << <>(ostream &salida, const Matriz<T> &mat);
  friend istream& operator >> <>(istream &entrada, Matriz<T> &mat);
};

template <class T>
Matriz<T>::Matriz(int filas = 0, int columnas = 0) : nfilas(filas), ncolumnas(columnas)
{
  if (nfilas > 0 and ncolumnas > 0)
  {
    matr = new T* [filas];
    for (int i = 0; i < filas; ++i) matr[i] = new T [columnas];
  }
}
 
template <class T>
Matriz<T>::Matriz(const Matriz &m)
{
  *this = m;
}
 
template <class T>
Matriz<T>::~Matriz()
{
  borrar();
}
 
template <class T>
void Matriz<T>::borrar()
{
  if (this->matr != NULL)
  {
    for (int i = 0; i < nfilas; ++i) delete[] matr[i];
    delete[] matr;
    matr = NULL;
  }
}
 
template <class T>
int Matriz<T>::filas() const
{
  return nfilas;
}
 
template <class T>
int Matriz<T>::columnas() const
{
  return ncolumnas;
}
 
template <class T>
T Matriz<T>::consultar(int fila, int columna) const
{
  return matr[fila][columna];
}
 
template <class T>
void Matriz<T>::modificar(int fila, int columna, T x)
{
  matr[fila][columna] = x;
}
 
template <class T>
Matriz<T>& Matriz<T>::operator =(const Matriz &mat)
{
  if (this != &mat)
  {
    this->borrar();
 
    if (mat.matr)
    {
      this->nfilas = mat.nfilas;
      this->ncolumnas = mat.ncolumnas;
 
      this->matr = new T* [nfilas];
      for (int i = 0; i < nfilas; ++i)
        this->matr[i] = new T [ncolumnas];
 
      for (int i = 0; i < nfilas; ++i)
      {
        for (int j = 0; j < ncolumnas; ++j)
          this->matr[i][j] = mat.matr[i][j];
      }
    }
  }
  return *this;
}
 
template <class T>
void Matriz<T>::operator +=(const Matriz &mat)
{
  if (this->nfilas != 0 and this->ncolumnas != 0 and mat.nfilas != 0 and mat.ncolumnas != 0)
  {
    for (int i = 0; i < nfilas; ++i)
      for (int j = 0; j < ncolumnas; ++j)
        this->matr[i][j] += mat.matr[i][j];
  }
}
 
template <class T>
void Matriz<T>::operator -=(const Matriz &mat)
{
  if (this->nfilas != 0 and this->ncolumnas != 0 and mat.nfilas != 0 and mat.ncolumnas != 0)
  {
    for (int i = 0; i < nfilas; ++i)
      for (int j = 0; j < ncolumnas; ++j)
        this->matr[i][j] -= mat.matr[i][j];
  }
}
 
template <class T>
Matriz<T> Matriz<T>::operator +(const Matriz &b) const
{
  int filas = this->nfilas;
  int columnas = this->ncolumnas;
 
  Matriz<T> res(filas, columnas);
 
  for (int i = 0; i < filas; ++i)
    for (int j = 0; j < columnas; ++j)
      res.matr[i][j] = this->matr[i][j] + b.matr[i][j];
 
  return res;
}
 
template <class T>
Matriz<T> Matriz<T>::operator -(const Matriz &b) const
{
  int filas = this->nfilas;
  int columnas = this->ncolumnas;
 
  Matriz<T> res(filas, columnas);
 
  for (int i = 0; i < filas; ++i)
    for (int j = 0; j < columnas; ++j)
      res.matr[i][j] = this->matr[i][j] - b.matr[i][j];
 
  return res;
}
 
template <class T>
Matriz<T> Matriz<T>::operator *(const Matriz &b) const
{
  if (this->ncolumnas == b.nfilas)
  {
    int pos = this->ncolumnas;
 
    int filas = this->nfilas;
    int columnas = b.ncolumnas;
 
    Matriz<T> res(filas, columnas);
    for (int i = 0; i < filas; ++i)
    {
      for (int j = 0; j < columnas; ++j)
      {
        T value = 0;
        for (int k = 0; k < pos; ++k) value += this->matr[i][k] * b.matr[k][j];
        res.matr[i][j] = value;
      }
    }
    return res;
  }
}
 
template <class T>
Matriz<T> Matriz<T>::operator *(int b) const
{
  int filas = this->nfilas;
  int columnas = this->ncolumnas;
 
  Matriz res(filas, columnas);
  for (int i = 0; i < filas; ++i)
    for (int j = 0; j < columnas; ++j) res.matr[i][j] = this->matr[i][j] * b;
 
  return res;
}
 
template <class T>
Matriz<T> operator *(int a, const Matriz<T> &b)
{
  return b*a;
}
 
template <class T>
bool Matriz<T>::operator ==(const Matriz &b) const
{
  if (this->nfilas != b.nfilas or this->ncolumnas != b.ncolumnas) return false;
  for (int i = 0; i < this->nfilas; ++i)
    for (int j = 0; j < this->ncolumnas; ++j)
      if (this->matr[i][j] != b.matr[i][j]) return false;
 
  return true;
}
 
template <class T>
bool Matriz<T>::operator !=(const Matriz<T> &b) const
{
  if (this->nfilas != b.nfilas or this->ncolumnas != b.ncolumnas) return true;
  for (int i = 0; i < this->nfilas; ++i)
    for (int j = 0; j < this->ncolumnas; ++j)
      if (this->matr[i][j] != b.matr[i][j]) return true;
 
  return false;
}
 
template <class T>
ostream& operator <<(ostream &salida, const Matriz<T> &mat)
{
  for (int i = 0; i < mat.nfilas; ++i)
  {
    for (int j = 0; j < mat.ncolumnas; ++j) salida << mat.matr[i][j] << " ";
    salida << endl;
  }
  return salida;
}
 
template <class T>
istream& operator >>(istream &entrada, Matriz<T> &mat)
{
  for (int i = 0; i < mat.nfilas; ++i)
    for (int j = 0; j < mat.ncolumnas; ++j) entrada >> mat.matr[i][j];
  return entrada;
}


Pues bien, como podéis comprobar he arreglado el problema que tenia con las funciones friend y los templates implementando las sobrecargas como métodos de la clase y añadiendo una pre-especificación que está comentada con un enlace, dónde se explica la solución al error de las sobrecargas de iostream (parece que el problema venía por temas internos de la clase iostream que no interpretaba bien operaciones internas de los templates). La sobrecarga del operador de un entero por una matriz he tenido que declararlo como externo a la clase, ya que si se declara como método cogerá el parámetro implícito como primer parámetro de la operación.

El resto de cambios son por la implementación de los templates.

Si alguien tiene alguna duda o sugerencia, será bienvenida ^^

Saludos y gracias amchacon por toda la ayuda!

PD: Iré mejorando la clase, como ya dije quiero implementar Gauss y varias cosas más, pero de momento voy a centrarme en el estudio de punteros que para mitades de enero tengo el examen final de programación y quiero mi matricula  ;-)
"The programmers of tomorrow are the wizards of the future" - Gave Newel