Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[C++] Duda con new y delete o delete[]

Estas en el tema de [C++] Duda con new y delete o delete[] en el foro de C/C++ en Foros del Web. Estaba investigando como hacer matrices dinamicas y en una parte lei que podia hacerlo con new, entonces yo lo implemente de esta forma. @import url("http://static.forosdelweb.com/clientscript/vbulletin_css/geshi.css"); ...
  #1 (permalink)  
Antiguo 20/03/2013, 21:58
 
Fecha de Ingreso: noviembre-2011
Mensajes: 50
Antigüedad: 12 años, 5 meses
Puntos: 3
Pregunta [C++] Duda con new y delete o delete[]

Estaba investigando como hacer matrices dinamicas y en una parte lei que podia hacerlo con new, entonces yo lo implemente de esta forma.

Código C++:
Ver original
  1. void crearMatriz(int **m) {
  2.         for (i=0; i<n; i++)
  3.         m[i] = new int[n];
  4.  }
  5.  
  6. int main() {
  7.     int **matriz1;
  8.    
  9.     matriz1 = new int *[n];
  10.  
  11.         crearMatriz(matriz1);

El problema es que no se como hacer el delete correspondiente, ¿alguien me ayuda?.
  #2 (permalink)  
Antiguo 21/03/2013, 12:56
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: [C++] Duda con new y delete o delete[]

La idea es simple: para cada new necesitas un delete, y si usas un new para mas de un elemento necesitas un delete para mas de un elemento

Código:
#define FILAS 3
#define COLUMNAS 5

void crearMatriz(int **m) {
	for(int i = 0; i < FILAS; i++) {
		m[i] = new int[COLUMNAS];//creas las columnas de cada fila
	}
}
     
int main() {
	int **matriz1;
	
	matriz1 = new int *[FILAS];//creas las filas
	
	crearMatriz(matriz1);
	
	for(int i = 0; i < FILAS; i++) {
		delete [] matriz1[i] ;//eliminas las columnas de cada fila
	}
	delete [] matriz1;//eliminas las filas
	
	return 0;
}
Para hacerlo bien faltan las comprovaciones de error, y asignar el valor nulo a las variables nulas. Aunque creo que seria mas apropiado dejar que la funcion cree tambien las filas en vez de solo las columnas no?

Saludos
vosk
  #3 (permalink)  
Antiguo 21/03/2013, 13:03
 
Fecha de Ingreso: julio-2012
Mensajes: 375
Antigüedad: 11 años, 9 meses
Puntos: 28
Respuesta: [C++] Duda con new y delete o delete[]

Cita:
Iniciado por vosk Ver Mensaje
Para hacerlo bien faltan las comprovaciones de error, y asignar el valor nulo a las variables nulas.
Si colocas parentesis en new() las variables se inicializan a cero (si fuesen objetos, se llamaría al constructor por defecto).
  #4 (permalink)  
Antiguo 21/03/2013, 13:28
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: [C++] Duda con new y delete o delete[]

Si, pero con el delete no se cumple, debes asignar nulo manualmente a lo que quieras que sea nulo. Y en c++ no se si sucede (creo que se comporta igual pero no lo se), pero en C al declarar una variable no inicializada se le asigna un valor basura, por eso si se necesita un puntero no inicializado a algo debe asignarlese manualmente el valor nulo para que se manipule correctamente y se comporte como un valor nulo

Código:
int **matriz = NULL;//no se si es necesario en c++

...
delete [] matriz1;
matriz1 = NULL;
Saludos
vosk
  #5 (permalink)  
Antiguo 21/03/2013, 14:17
 
Fecha de Ingreso: julio-2012
Mensajes: 375
Antigüedad: 11 años, 9 meses
Puntos: 28
Respuesta: [C++] Duda con new y delete o delete[]

Ah te refieres a que el puntero apunte a NULL.

Bueno eso depende, si el puntero va a dejar de ser utilizable despues del delete (por un fin de llave) no es imprescindible que pongas NULL.
  #6 (permalink)  
Antiguo 21/03/2013, 15:39
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: [C++] Duda con new y delete o delete[]

"... si el puntero va a dejar de ser utilizable despues del delete (por un fin de llave) no es imprescindible que pongas NULL..."

Por un fin de llave:

Es muy recomendable y (creo yo) imprescindible que pongas NULL, de lo contrario no puedes hacer comprovaciones de error y puedes enviar ese puntero a funciones que intenten usarlo por no ser nulo y que revienten la aplicacion. Es practicamente necesario tanto lo de asignar nulo como lo de las comprovaciones de error para solucionar casos de salida inesperada, o error en cargas iniciales, etc, donde sales con una unica funcion que se encarga de finalizar todo lo inicializado (a menos que quieras hacer tantas funciones de salida como posibles errores). Un fin de llave no asegura que ese puntero deje de usarse.

Por un fin de llave y de scope:

Si deja de ser utilizable por fin de llave y de scope entonces no será necesario.

En el caso del ejemplo no es necesario, porque liberas el puntero y sales de la aplicacion. En casos mas complejos el echo de asignar nulos te salva de comentarios tales como "que raro, en casa funcionaba y en la oficina cliente peta el programa". No solo en esos casos, sino incluso es habitual que algunas librerias lleven la macro safe_release cuya implementacion consiste en un condicional que comprueba que no sea nulo y las funciones necesarias de liberacion.

Personalmente creo que es una buena practica no dejar esos cabos sueltos. Para eso incluso el 'new' implementa el modo nothrow para asignar nulo en caso de error y poder hacer todo eso (de lo contrario no tendria sentido).

Saludos
vosk
  #7 (permalink)  
Antiguo 21/03/2013, 22:17
 
Fecha de Ingreso: noviembre-2011
Mensajes: 50
Antigüedad: 12 años, 5 meses
Puntos: 3
Respuesta: [C++] Duda con new y delete o delete[]

Cita:
Iniciado por vosk Ver Mensaje
La idea es simple: para cada new necesitas un delete, y si usas un new
Para hacerlo bien faltan las comprovaciones de error, y asignar el valor nulo a las variables nulas. Aunque creo que seria mas apropiado dejar que la funcion cree tambien las filas en vez de solo las columnas no?
¿Como podria hacer las comprobaciones de error?.

Lo segundo, no hacia que las funciones crearan las filas por que al hacer eso me pasaban cosas raras, en Ubuntu y WIndows me compilaba sin ningun error (solo con una advertencia), pero al ejecutarlo a veces veia mensajes de error raros y bueno, me funciono bastante raro la cosa, pero como regla general y depues de varios intentos encontre que si hacia la funcion asi como lo tengo, pero ahora que leo tus mensajes pienso que puede ser eso de las comprobaciones e inicializar los int **m, int **r, etc... en NULL (o quizas el comportamiento extraño era por otra cosa ahora que lo pienso pero no lo tengo claro todavia). Lo de asignarles NULL despues de los delete[] no serian necesarios en mi programa ya que libero la memoria justo antes del return de la funcion main.

Saludos y gracias por el aporte.

EDIT: Solo edito esto para decir que ya probe inicializandos las matrices en NULL, y ahora me sigue dando errores en windows, y en ubuntu compilando solo con terminal me funciona bien, el error que leo en windows dice "terminate called after trowhing an instance of std::bad_alloc. This app has requested.... bla bla bla", asi que debe ser algo de eso de corroborar o hacer algo mas aparte, pero me parece muy extraño el tener comportamientos diferentes con el mismo codigo, nunca me habia pasado xD. Quiero arreglarlo, me hace sentir que el codigo no es estable...

Última edición por ElPatoGarrido; 21/03/2013 a las 22:48
  #8 (permalink)  
Antiguo 22/03/2013, 05:46
 
Fecha de Ingreso: julio-2012
Mensajes: 375
Antigüedad: 11 años, 9 meses
Puntos: 28
Respuesta: [C++] Duda con new y delete o delete[]

Cita:
Iniciado por vosk Ver Mensaje
Por un fin de llave y de scope:

Si deja de ser utilizable por fin de llave y de scope entonces no será necesario.

En el caso del ejemplo no es necesario, porque liberas el puntero y sales de la aplicacion.
Me referia a un caso como este:

Código:
void Ejemplo()
{
  int** Cosita;

  //...

  delete[] Cosita;
}
Despues del delete, el puntero "desaparece" porque finaliza su ambito. No es posible cometer ningún error porque ya no existe el puntero.

Para el resto de los casos si habría que poner el NULL claro ;)

Cita:
pero me parece muy extraño el tener comportamientos diferentes con el mismo codigo, nunca me habia pasado xD. Quiero arreglarlo, me hace sentir que el codigo no es estable...
Asi son los punteros, lo pruebas una vez y parece que funcionan. Luego al día siguiente fallan. No esque los punteros sean inestables, es que si se usan mal pueden ser muy engañosos.

El bad alloc suele lanzarse cuando no se puede reservar la memoria... Cuantos elementos has reservado? Has puesto algun tipo de bucle infinito?
  #9 (permalink)  
Antiguo 22/03/2013, 06:16
 
Fecha de Ingreso: noviembre-2011
Mensajes: 50
Antigüedad: 12 años, 5 meses
Puntos: 3
Respuesta: [C++] Duda con new y delete o delete[]

Cita:
Iniciado por amchacon Ver Mensaje
Me referia a un caso como este:
El bad alloc suele lanzarse cuando no se puede reservar la memoria... Cuantos elementos has reservado? Has puesto algun tipo de bucle infinito?
No, solo tengo fors de 0 hasta 'n' y llamadas a funciones, el codigo esta aqui: http://pastie.org/7065892#4 (aun que le quite bastante codigo, pero eran funciones como la de sumarMatriz y cosas por el estilo), ahora me pasa por la funcion crearMatriz(matriz1, n); o por llenarMatriz(matriz1, n); por que se me ha trabado despues de el cout << "Matriz 1:" << endl;, pero yo no veo nada raro, la verdad cada vez siento que entiendo menos el problema xD.

Última edición por ElPatoGarrido; 22/03/2013 a las 06:23
  #10 (permalink)  
Antiguo 22/03/2013, 08:11
 
Fecha de Ingreso: julio-2012
Mensajes: 375
Antigüedad: 11 años, 9 meses
Puntos: 28
Respuesta: [C++] Duda con new y delete o delete[]

El error es que no has inicializado n.

Tienes el compilador desactualizado? Tengo la última versión y me saltaba esa línea como "Precaución, variable no inicializada".

Última edición por amchacon; 22/03/2013 a las 08:31
  #11 (permalink)  
Antiguo 22/03/2013, 13:03
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 11 años, 8 meses
Puntos: 83
Respuesta: [C++] Duda con new y delete o delete[]

"...Para el resto de los casos si habría que poner el NULL claro ;) ..."

Ok estamos de acuerdo: a esos me referia, una unica funcion de inicio que llama a un rack de funciones de carga, y una unica funcion de final que llama a un rack de funciones de descarga.

Ojo lo de las variables no inicializadas: asumí que tenias el 'n' como global o lo que sea, por eso en el ejemplo puse un define para las filas y columnas. Si no inicializas una variable el sistema le asigna un valor basura que no tendrá sentido en el ambito de tu aplicacion (lo mismo sucede con los punteros, por si solos no se inician a nulo).

Para las comprovaciones de error: si no vas a usar objetos puedes usar el malloc - free de C y comprovar directamente un retorno nulo; si vas a usar objetos necesariamente usaras el new - delete. El 'new' genera por defecto excepciones para los casos de error, la buena practica pasa por comprovar las excepciones (echa un vistazo a try - catch, es la forma de hacerlo). Aun hay otra opcion para el 'new', consiste en forzar que no genere excepciones y retorne nulo en caso de cualquier error (ojo, por defecto no retorna nulo sino que genera una excepcion, no es lo mismo). En cualquier caso cuando trabajes con memoria dinamica es muy aconsejable hacer todas las comprovaciones de error.

Una forma de hacerlo con nothrow:

Código:
int **crear_matriz(int filas, int columnas) {
	int **matriz = 0;
	
	if(!(matriz = new (nothrow) int *[filas])) {
		return 0;
	}
	
	for(int f = 0; f < filas; f++) {
		if(!(matriz[f] = new (nothrow) int[columnas])) {
			return 0;
		}
	}
	
	return matriz;
}

void llenar_matriz(int **matriz, int filas, int columnas) {
	int i = 0;
	
	for(int f = 0; f < filas; f++) {
		for(int c = 0; c < columnas; c++) {
			matriz[f][c] = i++;
		}
	}
}

void volcar_matriz(int **matriz, int filas, int columnas) {
	for(int f = 0; f < filas; f++) {
		for(int c = 0; c < columnas; c++) {
			printf("%d\t", matriz[f][c]);
		}
		printf("\n");
	}
}

void vaciar_matriz(int **matriz, int filas, int columnas) {
	if(matriz) {
		for(int f = 0; f < filas; f++) {
			if(matriz[f]) {
				delete [] matriz[f] ;
			}
		}
		delete [] matriz;
	}
}

int main() {
	int **matriz, filas, columnas;
	
	matriz = 0;//en este caso no seria necesario
	filas = 3;
	columnas = 5;
	
	if((matriz = crear_matriz(filas, columnas))) {
		llenar_matriz(matriz, filas, columnas);
		volcar_matriz(matriz, filas, columnas);
	}
	vaciar_matriz(matriz, filas, columnas);
	
	getchar();
	return 0;
}
Puedes ver que en las comprovaciones de error puedo validar contra nulo porque se que en caso de error el nothrow me retornó un nulo.

Saludos
vosk

Etiquetas: delete, int, matriz
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 05:13.