Matrices dinámicas de objetos.

En C++ se pueden crear matrices dinámicas de objetos de múltiples formas, en función de las necesidades del programa. Una matriz dinámica es aquella en la cuál no se conocerán sus dimensiones hasta que se ejecute el programa, o bien puede ser redimensionada por necesidades del programa en tiempo de ejecución. Las distintas posibilidades de creación de una matriz dinámica de objetos son:

Al igual que en la anterior entrada sobre creación de matrices de objetos en C/C++: Matrices estáticas de Objetos, se usará la clase Point3D, la cual no es mas que un wrapper de tres enteros que representan un punto en un espacio euclídeo tridimensional. Observe que esta clase está dotada de un constructor sin argumentos:

class Point3D{
		int x;
		int y;
		int z;
	public:
		Point3D(){ x=y=z=0; };
		Point3D(int cx,int cy,int cz){ x=cx; y=cy; z=cz; };
		int getX(){return x;}
		int getY(){return y;}
		int getZ(){return z;}
		void setX(int cx){x=cx;};
		void setY(int cy){y=cy;};
		void setZ(int cz){z=cz;};
		friend ostream& operator<<(ostream &stream,const Point3D &point);
};

En este caso las dimensiones de la matriz se pasarán como parámetro de entrada al programa. Para controlar que las dimensiones de la matriz sean coherentes se ha creado la función controlarEntrada, esta función asegura que los valores de fila y de columna sean mayores que 0. A continuación se muestra el código de la función:

void controlarEntrada(int argc, char** argv,int* fil,int* col){
	if (argc < 3){
		cerr<< endl << "Use ./executable filas columnas" << endl << endl;
		exit(1);
	}

	*fil= atoi(argv[1]);
	*col= atoi(argv[2]);
	
	if(*fil<=0 || *col<=0){
		cerr<< endl << "El número de filas y columnas debe ser mayor que 0" << endl << endl;
		exit(1);
	}

	return;
}

Creando un vector dinámico de objetos

Aunque esta solución no es propiamente una matriz dinámica de objetos, a través de la aritmética de punteros podemos usar un vector cualquiera como si fuera una matriz, ya que tanto en C como en C++ las matrices son almacenadas en memoria como vectores en espacios contiguos de memoria.

//Ejemplo de creación de una matriz de objetos usando un vector de objetos
int main(int argc, char** argv){ 

	int fil=0,col=0;
	
	controlarEntrada(argc,argv,&fil,&col);
	
	int i,j;

	//Creo el vector de objetos
	Point3D *puntos = new Point3D[fil*col];

	//Imprimo los objetos punto
	for( i=0; i< fil; i++){
		for(j=0; j< col ; j++){
			cout << "punto[" << i << "][" << j << "] -> " << puntos[i*col + j];
		}
		cout << endl;
	}

	//Libero la memoria correspondiente al vector de objetos
	delete [] puntos;
	

	return 0;
}

Observe que la forma correcta de usar el vector como si fuera una matriz es mediante la aritmética de punteros, haciendo la operación (número de fila actual) * (número de objetos que hay en una fila) + (número de columna actual). En el código fuente esta operación viene representada por: puntos[i*col + j].

Pros:

  • Es sencillo definir un vector de objetos de tamaño dinámico.
  • Las operaciones de liberación de memoria son mas sencillas que en otras formas de operar con memoria dinámica.
  • En caso de que se necesite añadir una fila mas a la matriz de objetos, esta es la forma mas sencilla de hacerlo, ya que se maneja como un solo bloque de memoria.

Contras:

  • Todos los objetos creados serán iguales. Esto implica tener un constructor por defecto. Posteriormente a la creación, sera necesaria una segunda iteración sobre el vector para parametrizar los objetos.
  • El uso extensivo de aritmética de punteros puede inducir a errores de programación que deriven en accesos a secciones de memoria no consecutiva o no reservada. Este tipo de errores son bastante tediosos y difíciles de erradicar.

Creando una matriz dinámica de objetos

La forma de crear una matriz dinámica de objetos, es creando un puntero un vector de punteros a objeto. Y posteriormente hacer que cada puntero del vector apunte a un vector de objetos. Abajo se muestra el código de como sería el programa en este caso.

//Ejemplo de creación de una matriz de objetos usando una matriz dinámica de objetos
int main(int argc, char** argv){ 

	int fil=0,col=0;
	
	controlarEntrada(argc,argv,&fil,&col);
	
	int i,j;

	//Creo la matriz de objetos
	Point3D **puntos = new Point3D*[fil];
	for( i=0; i< fil; i++)
		puntos[i] = new Point3D[col];

	//Imprimo los objetos punto
	for( i=0; i< fil; i++){
		for(j=0; j< col ; j++){
			cout << "punto[" << i << "][" << j << "] -> " << puntos[i][j];
		}
		cout << endl;
	}

	//Libero la memoria correspondiente a la matriz de objetos
	for( i=0; i< fil; i++)
		delete [] puntos[i];
	delete [] puntos;
	

	return 0;
}	

Observe que en este caso la forma de acceder a los objetos de la matriz es igual que si fuera una matriz estática.

A la hora de liberar memoria hay que ir recorriendo la matriz por filas (puntero que apunta a un vector de objetos) e ir liberando los vectores de objetos for( i=0; i< fil; i++) delete [] puntos[i];. Finalmente hay que liberar el vector principal, o vector de punteros que apuntan a vectores de objetos delete [] puntos;.

Pros:

  • Se pueden definir matrices irregulares o en inglés “jagged arrays” (No todas las filas tienen la misma longitud).
  • El acceso a elementos de la matriz es mas sencillo que en otras formas de operar con memoria dinámica.
  • En caso de que se necesite redimensionar la matriz (añadir o eliminar filas), o bien redimensionar una de las filas de la matriz, esta es la forma mas sencilla de hacerlo

Contras:

  • Todos los objetos creados serán iguales. Esto implica tener un constructor por defecto. Posteriormente a la creación, sera necesaria una segunda iteración sobre el vector para parametrizar los objetos.
  • Las operaciones de liberar memoria y de creación de la matriz son mas complicadas que en el caso de el vector dinámico de objetos.

Creando un vector dinámico de punteros a objeto

Esta forma es muy similar a la primera forma vista en esta entrada. Solo que a diferencia de la primera, en lugar de crear un vector plano de objetos, aquí lo que se crea es un vector plano de punteros a objeto y posteriormente se usa la aritmética de punteros para desplazarse a través del vector de punteros a objeto como si se tratara de una matriz.

//Ejemplo de creación de una matriz de objetos usando un vector dinámico de punteros a objetos
int main(int argc, char** argv){ 

	int fil=0,col=0;
	
	controlarEntrada(argc,argv,&fil,&col);
	
	int i,j;

	//Creo el vector dinámico de punteros a objetos
	Point3D **puntos = new Point3D*[fil*col];
	for( i=0; i< fil; i++)
		for(j=0; j< col ; j++)
			puntos[i*col +j] = new Point3D(i,j,i*col+j);

	//Imprimo los objetos punto
	for( i=0; i< fil; i++){
		for(j=0; j< col ; j++){
			cout << "punto[" << i << "][" << j << "] -> " << *puntos[i*col +j];
		}
		cout << endl;
	}

	//Libero la memoria correspondiente al vector de punteros a objetos
	for( i=0; i< fil; i++)
		for(j=0; j< col ; j++)
			delete puntos[i*col +j];
	delete [] puntos;
	

	return 0;
}	

En esta forma de operar primero se reserva memoria para el vector de punteros, observe que se usa un doble asterisco, como si se tratara de una matriz de objetos. Posteriormente se inicializa el vector de punteros a objetos haciendo que cada puntero apunte a un objeto diferente.

Observe que en este caso la forma de acceder a los objetos de la matriz (vector) se hace mediante el operador de indirección combinado con aritmética de punteros *puntos[i*col +j];, ya que lo que se tiene en la matriz (vector) es un puntero y no el objeto en sí.

A la hora de liberar memoria en este caso hay que ir recorriendo la matriz (vector) elemento a elemento (puntero a puntero)for( i=0; i< fil; i++) for(j=0; j< col ; j++) delete puntos[i*col +j]; y liberando individualmente cada elemento. Finalmente hay que liberar el vector principal, o vector de punteros a objetos delete [] puntos;.

Pros:

  • Trabajar con punteros presenta ventajas a la hora de realizar ciertas operaciones, como ordenar, borrar elementos o sustituir elementos.
  • Se pueden parametrizar los objetos en el momento de creación.
  • Es sencillo y menos costoso para la máquina redimensionar el vector para añadir mas punteros a objeto al final.

Contras:

  • El acceso a los elementos de la matriz se hace mediante indirección, lo cuál puede inducir a errores de programación.
  • Las operaciones de liberar memoria y de creación de la matriz son mas complicadas que en otros casos
  • El hacer uso de aritmética de punteros y de indirección puede inducir a errores de programación que impliquen fugas de memoria o violaciones de segmento.

Creando una matriz dinámica de punteros a objeto

En este caso en lugar de crear una matriz de objetos, se crea una matriz dinámica de punteros a objeto, esto supone que la tarea de creación de la matriz es menos costosa para la máquina, ya que los bloques de memoria contiguos requeridos para la matriz son mucho menores.

//Ejemplo de creación de una matriz de objetos usando una matriz dinámica de punteros a objetos
int main(int argc, char** argv){ 

	int fil=0,col=0;
	
	controlarEntrada(argc,argv,&fil,&col);
	
	int i,j;

	//Creo la matriz dinámica de punteros a objetos
	Point3D ***puntos = new Point3D**[fil];
	for( i=0; i< fil; i++)
		puntos[i] = new Point3D*[col];

	for( i=0; i< fil; i++)
		for(j=0; j< col ; j++)
			puntos[i][j] = new Point3D(i,j,i*col+j);

	//Imprimo los objetos punto
	for( i=0; i< fil; i++){
		for(j=0; j< col ; j++){
			cout << "punto[" << i << "][" << j << "] -> " << *puntos[i][j];
		}
		cout << endl;
	}

	//Libero la memoria correspondiente a la matriz de punteros a objetos
	for( i=0; i< fil; i++){
		for(j=0; j< col ; j++)
			delete puntos[i][j];
		delete [] puntos[i];
	}
	delete [] puntos;
	

	return 0;
}		

En esta forma de operar primero se reserva memoria para el vector de punteros a vectores de punteros (filas) Point3D ***puntos = new Point3D**[fil];, observe que se usa un triple asterisco, ya que se tratara de una matriz de punteros a objetos. Posteriormente se reserva memoria para cada vector de punteros a objetos (columnas) for( i=0; i< fil; i++) puntos[i] = new Point3D*[col];. Y finalmente se crea de forma individual cada objeto.

Observe que en este caso la forma de acceder a los objetos de la matriz (vector) se hace mediante el operador de indirección *puntos[i][j];, ya que lo que se tiene en la matriz es un puntero y no el objeto en sí.

A la hora de liberar memoria en este caso hay que ir recorriendo la matriz elemento a elemento (puntero a puntero)for( i=0; i< fil; i++) for(j=0; j< col ; j++) delete puntos[i][j]; y liberando individualmente cada elemento. Posteriormente hay que liberar cada vector de punteros a objetos (filas) delete [] puntos[i];. Finalmente hay que liberar el vector principal, o vector de punteros a vectores de punteros a objetos delete [] puntos;.

Pros:

  • Trabajar con punteros presenta ventajas a la hora de realizar ciertas operaciones, como ordenar, borrar elementos o sustituir elementos.
  • Se pueden parametrizar los objetos en el momento de creación.
  • Es sencillo y menos costoso para la máquina crear o redimensionar la matriz de punteros

Contras:

  • El acceso a los elementos de la matriz se hace mediante indirección, lo cuál puede inducir a errores de programación.
  • Las operaciones de liberar memoria y de creación de la matriz son mucho mas complicadas que en otros casos
  • El hacer uso de aritmética de punteros y de indirección puede inducir a errores de programación que impliquen fugas de memoria o violaciones de segmento.

Descargas Disponibles:

Acerca de franciscoguemes

Ingeniero en Informática
Esta entrada fue publicada en C/C++. Guarda el enlace permanente.

5 respuestas a Matrices dinámicas de objetos.

  1. Yajaira dijo:

    Oralé, ¡qué padre tu blog! no sabía que tenías uno … pues me leo despacio esto y ya de a poco cuando me meta de lleno seguramente te encontrarás más comentarios😀 Saludines … Yaira.

  2. carlos dijo:

    holas podrias enseñar como en un matriz se inserta columnas y filas segun la posicion que el usuario decida….gracias

  3. muy bun post muxas gracias genio!!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s