El lenguaje C ++ tiene reglas específicas sobre cómo debe liberar la memoria a la que apunta un puntero. Estas reglas requieren que sepa cómo se asignó la memoria para liberarla correctamente.

Por ejemplo,

int *p = new int();
std::free(p);

Da como resultado un comportamiento indefinido. (Referencia)

En C ++ moderno, nos gusta usar punteros inteligentes siempre que sea posible, pero a veces podemos querer usar bibliotecas o funciones que asignen punteros sin formato. Supongamos que quiero usar una función de la forma:

char* NotMyFunction();

¿Cómo administro correctamente la memoria asignada por esta función?

c++
-4
Apollys supports Monica 12 sep. 2018 a las 23:34

3 respuestas

La mejor respuesta

No tengo suficiente conocimiento de C ++ como para decirlo por mí mismo, pero según lo que el usuario2079303 ha escrito en su respuesta, es Parece que la respuesta teórica a esta pregunta es que es imposible . Sin embargo, en la práctica hay muchas formas de abordar este problema.


1. Consulte la documentación

En la mayoría de los casos, si está desarrollando software que utiliza una biblioteca, debe tener documentación que proporcione esta información. De lo contrario, puede preguntarse si los beneficios de usar esta biblioteca realmente superan los costos.

2. Comprueba el código fuente

Si tiene acceso al código fuente, debería poder averiguar cómo se asigna la memoria en cuestión. Es muy probable que esto sea más difícil que la opción 1 , pero le da una respuesta definitiva, en lugar de una respuesta que alguien más escribió (que realmente debería ser correcto, pero no t tiene que ser).

3. Usa valgrind

Valgrind es una herramienta de utilidad de depuración, no una herramienta para probar la corrección (corrígeme si me equivoco), pero en ausencia de acceso directo a los recursos que necesitamos para responder a esta pregunta, puede ser muy útil. Podemos experimentar con el siguiente programa, donde imaginamos que en nuestra aplicación es posible que no tengamos acceso al cuerpo de MysteryFunctionOne y MysteryFunctionTwo:

#include <iostream>

int* MysteryFunctionOne() {
  return new int();
}

int* MysteryFunctionTwo() {
  return (int *) malloc(sizeof(int));
}

int main() {
  int* p1 = MysteryFunctionOne();
  int* p2 = MysteryFunctionTwo();

  std::cout << std::hex << p1 << std::endl << p2 << std::endl;

  // For illustrative purposes, suppose we free both pointers incorrectly
  free(p1);
  delete p2;

  return 0;
}


Si compilamos y ejecutamos el programa anterior con valgrind program_name, recibimos dos mensajes de error importantes, el primero de los cuales es:

Mismatched free() / delete / delete []
   at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x400A2E: main (in <path/to/program>)
 Address 0x5ab6c80 is 0 bytes inside a block of size 4 alloc'd
   at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x4009A3: MysteryFunctionOne() (in <path/to/program>)
   by 0x4009C8: main (in <path/to/program>)


Esto nos dice que hemos utilizado incorrectamente free en la función main. La mitad inferior del mensaje de error incluso nos permite saber que se utilizó operator new en MysteryFunctionOne(). Por lo tanto, sabemos que necesitamos delete el puntero devuelto por MysteryFunctionOne(), por lo que cambiamos

free(p1);

Para

delete p1;

El segundo mensaje de error que recibimos es análogo, y de él aprendemos que necesitamos free(p2).

En este caso, incluso sin leer el código fuente o la documentación, valgrind pudo guiarnos hacia la gestión correcta de la memoria. En general, esto puede no ser siempre el caso, pero es una opción a considerar en ausencia del código fuente o documentación relevante.

0
Apollys supports Monica 13 sep. 2018 a las 23:52

¿Cómo administro correctamente la memoria asignada por esta función?

Usted lee la documentación de esa función y hace lo que esa documentación le dice que haga y cuándo hacerlo, suponiendo que haya algo que hacer en primer lugar. Es importante recordar que no todos los punteros se refieren a la memoria dinámica.

Ejemplo: la especificación de strdup dice:

Devuelve un puntero a una cadena de bytes terminada en nulo, que es un duplicado de la cadena a la que apunta str1. El puntero devuelto debe pasarse a free para evitar una pérdida de memoria.

Si no hay documentación disponible, puede leer el código fuente para ver qué hace la función y actuar en consecuencia. Si la fuente tampoco está disponible, entonces estás en una situación de molestia y es posible que debas invertir en una bola de cristal.

Excluyendo las funciones estándar, las API de C que adquieren recursos como la memoria dinámica y devuelven un identificador (puntero en el caso de la memoria dinámica) generalmente proporcionan una función correspondiente para liberar el recurso. Ejemplo: SDL_CreateWindow y SDL_DestroyWindow.


¿sería correcto para mí inferir que estás diciendo lo siguiente? En general, si se le da un puntero sin formato en C ++, es imposible garantizar la gestión correcta de la memoria de este puntero.

No está claro a qué te refieres. Si sabe cómo administrar la memoria, puede hacerlo correctamente. Si no sabe cómo administrar la memoria (o si debe ser administrada por usted), entonces necesita una forma de encontrar el conocimiento. No hay una forma razonable en C ++ de escribir el programa de una manera que descubra (a través de la introspección) cómo y cuándo se debe liberar la memoria.

El tipo char* en sí mismo no dice nada acerca de cómo se debe tratar la memoria. Incluso el valor del puntero no le dice nada más que si es nulo, entonces no apunta a un objeto. Si el puntero no es nulo, puede apuntar a un objeto.

8
eerorika 12 sep. 2018 a las 21:41
int *p = new int();
std::free(p);

Eso es incorrecto, debería ser:

int *p = new int;
delete p;

O

int *p =  (int*) malloc(sizeof(int));
free(p);

Con respecto a char* NotMyFunction();, donde sea y como sea que asigne su char *, no olvide liberarlo o eliminarlo. No pierda el puntero, lo necesitará para liberar la memoria.

char *NotMyFunction()
{
char* s = new char[n];
...
return s;
}

Luego:

char* nmf = NotMyFunction();
...
delete[] mfc;
0
user10356313user10356313 13 sep. 2018 a las 03:40