2010-06-30 11 views
26

Tengo esta función:Cómo eliminar un puntero después de regresar a su valor dentro de una función

char* ReadBlock(fstream& stream, int size) 
{ 
    char* memblock; 
    memblock = new char[size]; 
    stream.read(memblock, size); 
    return(memblock); 
} 

La función se llama cada vez que tengo que leer bytes de un archivo. Creo que asigna memoria nueva cada vez que la uso, pero ¿cómo puedo liberar la memoria una vez que he procesado los datos dentro de la matriz? ¿Puedo hacerlo desde fuera de la función? ¿El procesamiento de datos mediante la asignación de bloques grandes ofrece un mejor rendimiento que la asignación y eliminación de pequeños bloques de datos?

Muchas gracias por su ayuda!

+8

+1. ¡Esta es una gran pregunta! Contiene muchos recién llegados a la asignación de memoria manual. – Anthony

+0

Esta es una pregunta terrible, los recién llegados deben aprender a usar un 'std :: string' o' std :: vector'. –

+5

@Mattieu: ¿En lugar de aprender cómo std :: string y std :: vector funcionan bajo el capó? Creo que es una buena pregunta, aunque puedo ser parcial porque es una que sigo teniendo yo mismo, ya que no quiero simplemente comenzar a usar bibliotecas aleatorias sin saber lo que están haciendo. – abelito

Respuesta

15

matrices dinámicas se liberan utilizando delete[]:

char* block = ReadBlock(...); 
// ... do stuff 
delete[] block; 

Idealmente, sin embargo no se utiliza la gestión de memoria manual aquí:

std::vector<char> ReadBlock(std::fstream& stream, int size) { 
    std::vector<char> memblock(size); 
    stream.read(&memblock[0], size); 
    return memblock; 
} 
+2

Con este método, cuando se devuelve el objeto vector, se llama su constructor de copia (es decir, ¿existen dos instancias en un punto)? – dreamlax

+4

@dream: Depende, muy probablemente * la optimización del valor de retorno *, [NRVO] (http://en.wikipedia.org/wiki/Return_value_optimization), se activará. Ver también la interesante [¿Quieres velocidad? Pase por valor.] (Http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/). –

+0

@Georg: publicación interesante, pero _todo el nombre engañoso. Casi suena como si estuvieran discutiendo el valor de paso por valor en lugar de pasar por referencia. Enlace cebo, supongo. – Stephen

5

Just delete[] el valor de retorno de esta función cuando haya terminado con ella. No importa que lo estés eliminando del exterior. Simplemente no lo elimines antes de terminar de usarlo.

+2

Tiene que ser 'delete []', not' delete'. –

+1

¡Ay! Lo triste es que si comete este error, el compilador ni siquiera puede detectarlo. Qué lenguaje tan horrible. Gracias de todos modos. Arreglaré la publicación. (Aunque debe decirse, en realidad no estaba proponiendo toda la línea de código, solo qué usar de manera predeterminada). – sigfpe

1

Sí. Puede llamar eliminar desde fuera de la función. Sin embargo, en este caso, ¿puedo sugerir el uso de std :: string para que no tenga que preocuparse por la gestión usted mismo?

+0

Ok, pero no puedo usar cadenas debido a la lectura. istream & read (char * s, streamsize n); – Emer

+0

Luego usa un vector en su lugar. Lo siento, no lo noté. –

4

Usted puede llamada:

char * block = ReadBlock(stream, size); 
delete [] block; 

Pero ... eso es un montón de asignación del montón sin ganancia. Considerar la adopción de este enfoque

char *block = new char[size]; 
while (...) { 
    stream.read(block, size); 
} 
delete [] block; 

* Nota, si size puede ser una constante en tiempo de compilación, sólo puede apilar asignar block.

+0

Llamada sólida al pasar un puntero estático a la función. +1 –

+1

Las matrices de tamaño variable no son ISO C++, es una extensión GCC. –

+0

@wowus: ¿Quién dice que el tamaño no es el tiempo de compilación? – Stephen

1

primero a destacar: la memoria asignada con el nuevo y borrar está completamente global. las cosas no se eliminan automáticamente cuando los punteros salen del alcance o se sale de una función. siempre que tenga un puntero a la asignación (como el puntero que se devuelve allí), puede eliminarlo siempre y siempre que lo desee. el truco es asegurarse de que otras cosas no lo borren sin que lo sepas.

que es una ventaja con el tipo de estructura de función que tiene la función de lectura de fstream. es bastante claro que toda esa función va a hacer es leer el número de bytes de "tamaño" en el búfer que proporciona, no importa si ese búfer ha sido asignado usando nuevo, si es un búfer estático o global, o incluso un búfer local, o incluso solo un puntero a una estructura local. y también es bastante claro que la función no va a hacer nada más con el buffer que pasa una vez que le leen los datos.

Por otro lado, tome la estructura de su función ReadBlock; si no tienes el código para eso, sería complicado averiguar exactamente qué devuelve. ¿Está devolviendo un puntero a la memoria nueva? si es así, ¿espera que lo elimine? ¿Lo eliminará? ¿Si es así cuando? ¿es incluso un nuevo puntero? ¿simplemente está devolviendo una dirección a un búfer estático compartido? si es así, cuándo el búfer se volverá inválido (por ejemplo, sobrescrito por otra cosa)

mirando el código de ReadBlock, está claro que está devolviendo un puntero a la memoria nueva y está esperando que elimine cuando hayas terminado con eso. ese búfer nunca se sobrescribirá ni se invalidará hasta que lo elimine.

speedwise, esa es la otra ventaja de fsream.read: 'usted clasifica el buffer': USTED tiene la opción de elegir cuándo se asigna la memoria. Si va a "leer datos, procesar, eliminar el búfer, leer el búfer de eliminación de proceso de datos, ect ...." va a ser mucho más eficiente simplemente asignar un búfer (al tamaño máximo que necesitará, esto será el tamaño de su lectura individual más grande) y solo use eso para todo, como lo sugirió Stephen.

0

¿Qué le parece usar un memblock estático de char *; Se inicializará solo una vez y no asignará a memblock un nuevo espacio cada vez.

Cuestiones relacionadas