2010-11-22 18 views
7

Considere el siguiente programa en C++:Posible pérdida de memoria usando C++ cadena

#include <cstdlib> // for exit(3) 
#include <string> 
#include <iostream> 
using namespace std; 

void die() 
{ 
    exit(0); 
} 

int main() 
{ 
    string s("Hello, World!"); 
    cout << s << endl; 
    die(); 
} 

La ejecución de este a través valgrind muestra esto (alguna salida recortado por razones de brevedad):

==1643== HEAP SUMMARY: 
==1643==  in use at exit: 26 bytes in 1 blocks 
==1643== total heap usage: 1 allocs, 0 frees, 26 bytes allocated 
==1643== 
==1643== LEAK SUMMARY: 
==1643== definitely lost: 0 bytes in 0 blocks 
==1643== indirectly lost: 0 bytes in 0 blocks 
==1643==  possibly lost: 26 bytes in 1 blocks 
==1643== still reachable: 0 bytes in 0 blocks 
==1643==   suppressed: 0 bytes in 0 blocks 

Como se puede ver, hay una posibilidad de que se perdieron 26 bytes asignados en el montón. Sé que la clase std::string tiene una estructura de 12 bytes (al menos en mi arco x86 de 32 bits y el compilador GNU 4.2.4), y "Hello, World!" con un terminador nulo tiene 14 bytes. Si lo entiendo correctamente, la estructura de 12 bytes contiene un puntero a la cadena de caracteres, el tamaño asignado y el recuento de referencias (alguien me corrige si me equivoco aquí).

Ahora mis preguntas: ¿Cómo se almacenan las cadenas de C++ con respecto a la pila/montón? ¿Existe un objeto de pila para un std::string (u otros contenedores STL) cuando se declara?

P.S. He leído en algún lugar que valgrind puede informar un falso positivo de una pérdida de memoria en algunos programas C++ que utilizan contenedores STL (y "casi-contenedores" como std::string). No estoy demasiado preocupado por esta filtración, pero despierta mi curiosidad con respecto a los contenedores STL y la gestión de la memoria.

+1

morir ¿Por qué llamas() ?! – EboMike

+2

@EboMike: Escribí el '' función die() para separar el 'exit (0)' 'llamada desde main()'. Mi programa ahora tiene que transferir el control a una función llamada, en la cual la función 'exit (0)' "desconecta" la ejecución de este programa. Tenga en cuenta que este programa no tiene otro propósito útil que no sea por razones académicas. – pr1268

+4

Mi punto es que die() causa las filtraciones en primer lugar. Si estás decidido a tener un dado() allí, al menos pon el hilo en su propio alcance. – EboMike

Respuesta

7

Otros son correctos, tiene fugas porque está llamando a la salida. Para ser claros, la fuga no es la cadena asignada en la pila, sino la memoria asignada en el montón por la cadena. Por ejemplo:

struct Foo { }; 

int main() 
{ 
    Foo f; 
    die(); 
} 

no hará que valgrind informe una fuga.

la fuga es probable (en lugar de definido) porque tiene un puntero al interior de memoria asignada en el montón. basic_string es responsable de esto. Desde la cabecera en mi máquina:

clave
* A string looks like this: 
    * 
    * @code 
    *          [_Rep] 
    *          _M_length 
    * [basic_string<char_type>]   _M_capacity 
    * _M_dataplus       _M_refcount 
    * _M_p ---------------->    unnamed array of char_type 
    * @endcode 
    * 
    * Where the _M_p points to the first character in the string, and 
    * you cast it to a pointer-to-_Rep and subtract 1 to get a 
    * pointer to the header. 

ellos es que _M_p no apunta al inicio de la memoria asignada en el montón, que apunta al primer carácter de la cadena. Aquí hay un ejemplo simple:

struct Foo 
{ 
    Foo() 
    { 
     // Allocate 4 ints. 
     m_data = new int[4]; 
     // Move the pointer. 
     ++m_data; 
     // Null the pointer 
     //m_data = 0; 
    } 
    ~Foo() 
    { 
     // Put the pointer back, then delete it. 
     --m_data; 
     delete [] m_data; 
    } 
    int* m_data; 
}; 

int main() 
{ 
    Foo f; 
    die(); 
} 

Esto reportará una fuga probable en valgrind. Si comenta las líneas en las que me muevo, m_data valgrind informará 'todavía accesible'. Si elimina el comentario de la línea donde configuré m_data a 0, obtendrá una fuga definitiva.

El valgrind documentation tiene más información sobre las fugas probables y punteros interiores.

+0

Gracias por su respuesta. Esto explica mucho sobre las cadenas de C++ y su asignación. – pr1268

1

gcc STL tiene un grupo de memoria privada para contenedores y cadenas. Puedes apagar esto; mira en FAQ valgrind

http://valgrind.org/docs/manual/faq.html#faq.reports

+0

Aunque es cierto hace muchos años, en estos días la biblioteca estándar de GCC en su configuración predeterminada no usa ningún grupo de memoria. –

4

Por supuesto este "fugas", por exit ing antes s 's marco de pila se deja usted no da s' s destructor oportunidad de ejecutar.

En cuanto a su pregunta wrt std::string almacenamiento: Las diferentes implementaciones hacen cosas diferentes. Algunos asignan unos 12 bytes en la pila que se usa si la cadena tiene 12 bytes o menos. Las cadenas más largas van al montón. Otras implementaciones siempre van al montón. Algunos son de referencia contada y con semántica de copia sobre escritura, otros no. Diríjase a Scott Meyers 'Effective STL, artículo 15.

1

Evitaría usar exit() No veo ninguna razón real para usar esa llamada. No estoy seguro si hará que el proceso se detenga instantáneamente sin limpiar primero la memoria aunque valgrind aún parece ejecutarse.

11

Llamando exit "finaliza el programa sin salir del bloque actual y, por lo tanto, sin destruyendo los objetos con duración de almacenamiento automático".

En otras palabras, fugas o no, realmente no debería importarle. Cuando llamas al exit, dices "cierra este programa, ya no me importa nada". Así que deja de preocuparte. :)

Obviamente va a perder recursos porque nunca dejes que se ejecute el destructor de la cadena, independientemente de cómo gestione esos recursos.

+0

relacionada con multi-threading, hace que todo el proceso se detiene si 'exit' se llama desde dentro de un hilo hijo, o sólo el hilo en el que se llamaba? –

+0

@Matt: Hasta donde puedo leer, actúa como si los otros hilos no existieran, luego hace lo mismo. Es decir, se limpian las estáticas locales de la secuencia, luego la estática del programa, etc. – GManNickG

Cuestiones relacionadas