2009-12-18 10 views
8

Estoy investigando una pérdida de memoria y por lo que veo, el problema se ve así:C++ asignación de memoria dinámica en una función - pregunta novato

int main(){ 
    char *cp = 0; 
    func(cp); 
    //code 
    delete[] cp; 
} 

void func(char *cp){ 
    cp = new char[100]; 
} 

En el comentario // código, que esperaba a cp apuntar a la memoria asignada, pero sigue siendo un puntero nulo, lo que significa que nunca elimino la memoria. ¿Qué estoy haciendo wroing?

+1

Supongo que 'cbuf' se suponía que era' cp'? – GManNickG

+0

¿qué tal postulando un código real? A menos que se corte y pegue el código, existe la posibilidad de que agregue errores. Esto solo hace que Thigs sea más difícil y terminamos resolviendo los errores de cortar y pegar como cbuf -> cp –

+0

Lo siento, lo tendré en cuenta para la próxima vez. Sí se suponía que cbuf debía ser cp –

Respuesta

11
void func(char *cp){ 
    cp = new char[100]; 
} 

En esta función, char * Cp es un "puntero ser adelantado por copia" lo que significa que están apuntando a la misma dirección de memoria, pero no son el mismo puntero . Cuando cambie el puntero en el interior, haciendo que apunte a otro lugar, el puntero original que se ha pasado seguirá apuntando a 0.

+0

Gracias, lo resolvió bien. Explicación muy clara. –

+0

@David: Gracias :) –

6

El parámetro cp es una variable local de la función, cambiarla no altera nada fuera de la función. Una mejor manera de escribir la función es:

char * func(){ 
    return new char[100]; 
} 

Y no hay que ver directamente con su pregunta, pero probablemente debería usar std :: string y std :: vector en lugar de matrices asignados dinámicamente.

+1

Hmm, dos votos a la baja. No es que me preocupe particularmente, pero otros aquí podrían beneficiarse de saber qué está mal con esta respuesta. –

+0

Nada que yo pueda ver. Si va a señalar algo como las características de C++ que mencionó, creo que probablemente también sea bueno agregar una parte sobre no codificar el tamaño de la matriz. Además, si vas a utilizar esas características particulares, probablemente quieras pasar un puntero a uno por referencia para crearlo, o bien pasar uno por referencia para evitar la penalización del constructor de copia ... pero realmente no hay nada INCORRECTO con esta respuesta. –

+0

Los punteros no tienen un constructor de copia. –

16

Está asignando cp el valor de la memoria asignada. Sin embargo, esa es una variable en la pila: ¡una copia de cp en main! cp es local a la función que está en

Lo que queremos es una referencia:..

void func(char *& cp) 

Esto alias a cp ser el parámetro pasado en

1

Usted está pasando en cbuf , no cp.

+0

incluso si pasaba * cp, seguiría apuntando a 0 después // código –

+1

Eso no importa, porque también lo está pasando por valor. – mob

1

La función solo está cambiando una COPIA de cp. Use una referencia en su lugar.

0

Como se mencionó GMan y Neil, con el fin de trabajar tendrá que cambiar a func:

char* func();

o void func(char*& p);

la que va a resolver su problema inmediato.

Hay, sin embargo, un problema de mantenimiento. En cualquier caso, func devuelve un puntero. Lo que no está claro para el usuario de func es que el puntero devuelto tendrá que ser eliminado. Por esta razón, generalmente evite esta construcción a menos que sea 100% necesario. Más bien:

  1. ayudar al usuario asignar la cantidad correcta de memoria que luego se puede pasar a func
  2. utilizar un objeto para almacenar la memoria asignada. El objeto puede eliminar la matriz de caracteres cuando se destruye.

Así que para el código C++, lo recomiendo:


class CBuf 
{ 
public 
    CBuf() 
    { 
     iBuf = new char[100]; 
    } 
    ~CBuf 
    { 
     delete[] iBuf; 
    } 
    char* func() 
    { 
     //do stuff; 
     return iBuf; 
    } 
private: 
    char* iBuf; 
}; 

int main() 
    { 
    CBuf cb; 
    char* mychar = cb.func(); 
    //do stuff with character array 

    //destructor gets called here because cb goes out of scope 
    } 

Sin embargo, en la programación de C en especial, podría ser 100% necesario tener alguna función de clasificación para crear la matriz. Por lo tanto, en la programación C puede reemplazar el destructor con una función CreateCBuf y DestroyCBuf. De esta forma, el usuario de su biblioteca sabrá que el buffer devuelto debe ser destruido.

+0

¿Puedo preguntar qué pasa con 'std :: vector'? – GManNickG

+0

std: vector está bien. Maneja toda la administración de memoria por usted. El problema en el ejemplo de OP es que la propiedad no está muy clara. – doron

1

Aunque las referencias son maravillosos en ofrecer una abstracción intuitiva, reforzada por C++ 11 referencias rvalue para permitir el encadenamiento de la función (y otros códigos esotéricos), se puede argumentar que proporcionan ninguna seguridad (es decir why is a reference considered safer than a pointer) Hay casos donde es mejor resolver lo anterior con un puntero al argumento de función de puntero. Específicamente cuando existe la necesidad de mantener una base de código similar en ansi c y C++.

#include <iostream> 

using namespace std; 

void func(char ** cp) { 
    *cp = new char[100]; 
    //do something useful 
    (*cp)[0] = 'A'; 
} 

void func(char *& cp) { 
    cp = new char[100]; 
    //do something useful 
    cp[0] = 'B'; 
} 

int main(int argc, char** argv) { 
    char * cp; 
    //pointer to pointer 
    func(&cp); 
    cout << "Index 0 : " << cp[0] << '\n' << flush; 
    delete[] cp; //remember to delete!! 
    //pointer to ref 
    func(cp); 
    cout << "Index 0: " << cp[0] << '\n' << flush; 
    delete[] cp; 
    return 0; 
} 

Por supuesto, la disposición de los recursos de memoria fuera del alcance de la función instatiating desobedece RAII.

Cuestiones relacionadas