2012-04-10 19 views
9

Soy nuevo en el mundo de los punteros inteligentes. He hecho mi lectura y todos declararon que los punteros inteligentes evitarán la pérdida de memoria incluso cuando el programa salga después de encontrar una excepción.Fugas de C++ en caso de excepción incluso mediante el uso de punteros inteligentes

Escribí un programa simple para probar esto, pero Valgrind me dice que mi programa está perdiendo memoria (tres allocs y solo uno libre).

Este es el código fuente:

#include <iostream> 
#include <memory> 

using namespace std; 

int main() 
{ 
    auto_ptr<int> ptr_int(new int(5)); 

    throw std::bad_alloc(); 

    cout << *ptr_int; 
} 

Y este informe Valgrind:

==27862== Memcheck, a memory error detector 
==27862== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. 
==27862== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info 
==27862== Command: ./smart_pointers 
==27862== Parent PID: 5388 
==27862== 
==27862== 
==27862== HEAP SUMMARY: 
==27862==  in use at exit: 104 bytes in 2 blocks 
==27862== total heap usage: 3 allocs, 1 frees, 120 bytes allocated 
==27862== 
==27862== 4 bytes in 1 blocks are still reachable in loss record 1 of 2 
==27862== at 0x4026351: operator new(unsigned int) (vg_replace_malloc.c:255) 
==27862== by 0x804878A: main (smart_pointers.cpp:8) 
==27862== 
==27862== 100 bytes in 1 blocks are possibly lost in loss record 2 of 2 
==27862== at 0x4025BD3: malloc (vg_replace_malloc.c:236) 
==27862== by 0x40E861A: __cxa_allocate_exception (in /usr/lib/libstdc++.so.6.0.14) 
==27862== by 0x80487AE: main (smart_pointers.cpp:10) 
==27862== 
==27862== LEAK SUMMARY: 
==27862== definitely lost: 0 bytes in 0 blocks 
==27862== indirectly lost: 0 bytes in 0 blocks 
==27862==  possibly lost: 100 bytes in 1 blocks 
==27862== still reachable: 4 bytes in 1 blocks 
==27862==   suppressed: 0 bytes in 0 blocks 
==27862== 
==27862== For counts of detected and suppressed errors, rerun with: -v 
==27862== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 19 from 8) 

¿El uso de punteros inteligentes garantizan los recursos asignados serán destruidas incluso si una excepción aparezca?

+4

No haber cogido la excepción en absoluto, por lo que termina llamando 'terminar()' cuyo comportamiento por defecto es llamar 'abortar()'. ¿Qué pasa si captas la excepción? –

+0

Si está utilizando un sistema operativo moderno, el sistema operativo recuperará la memoria utilizada por el programa cuando se cierre, por lo que no debe preocuparse por la pérdida de memoria per se.Por supuesto, es una situación diferente si está usando recursos que necesita limpiar explícitamente. – TheJuice

Respuesta

5

Cuando se llama std::terminate() (como es el caso de una excepción no detectada), la limpieza normal no se ejecuta (al menos para la pila marco de main()), y como tal, la memoria que ha asignado en esa pila filtraciones de marco, a pesar de que supuestamente es administrado por un puntero inteligente. Cuando atrapa el std::bad_alloc en main() y regresa normalmente, el puntero inteligente lo hará.

+0

Cambiar esa oración a "punteros inteligentes evitará la pérdida de memoria incluso en el caso de _handled_ execptions". No estás manejando la excepción. – modelnine

+0

mover el código a foo() no ayudará si no detecta la excepción. Si no atrapa una excepción (en cualquier lugar), entonces su aplicación terminará y los destructores no serán llamados (lo que sería el punto: el sistema operativo recuperaría automáticamente toda la memoria en este caso). usa esto: prueba { \t \t foo(); \t} catch (std :: bad_alloc ex) \t { \t} continuación, debería ver la memoria desasigna correctamente – skimon

+2

No sé sobre C++ 11, pero en un principio, en C++ fue hasta la puesta en práctica si los destructores son llamados en una excepción no controlada. A partir del punto: algunos destructores hacen más que reclamar memoria (por ejemplo, cerrar las conexiones del servidor, eliminar archivos temporales, ...). Por lo tanto, se podría argumentar que tiene sentido llamar a los destructores incluso en este caso. Sin embargo, dado que es trivial agregar un catch-all a 'main' y no desenrollar la pila puede ayudar con la depuración, no fue obligatorio. No sé si hay alguna implementación que desenrolle la pila para excepciones no detectadas. – celtschk

12

Si no se maneja una excepción, se define su implementación si la pila se desenrollará antes de llamar al std::terminate.

Si maneja la excepción, el puntero inteligente funcionará como se espera.

Referencia:

C++ 11 15.5.1 El std::terminate() función

1 En un manejo situaciones excepción debe ser abandonada para las técnicas de manejo de errores menos sutiles. Estas situaciones son:

........

- cuando el mecanismo de manejo de excepciones no puede encontrar un controlador para una excepción lanzada, o

........

2 En tales casos se llama std::terminate(). En la situación en la que no se encuentra ningún controlador coincidente, está definido por la implementación si la pila se desenrolla o no antes de que std::terminate() se llame.

+0

Me tomé la libertad de agregar la referencia estándar, espero que no te importe. –

2

Si no se detecta la excepción, el desenrollado de la pila es específico de la implementación. Por lo tanto, en su caso, no libera la memoria.

Además, auto_ptr ya no se recomienda.

uso std :: unique_ptr:

unique_ptr<int> ptr_int(new int(5)); 
+0

Gracias. Soy consciente de unique_ptr. – efabor

+0

Para dejar la limpieza principal() Moví el código a foo() Pero sigue el mismo problema. Creo que si las excepciones no se gestionan, los punteros inteligentes no sirven de nada. Sin embargo todo el Iv lectura hace que declararon "punteros inteligentes evitarán pérdidas de memoria, incluso en el caso de execptions" # include # include usando namespace std; void foo() { \t auto_ptr ptr_int (new int (5)); \t throw std :: bad_alloc(); \t cout << * ptr_int; } int main() { \t foo(); \t cout << "END"; } – efabor

+0

Acerca de la lectura: una excepción terminará su proceso y luego toda la memoria se liberará de todos modos. Debería preocuparse por una excepción no detectada más que por una fuga de recursos. '# include # include using namespace std; int func() { \t unique_ptr ptr_int (new int (5)); \t throw std :: bad_alloc(); \t cout << * ptr_int; \t return 0; } int main() { \t tratar \t { \t \t func(); \t} \t captura (...) \t { \t \t tribunal << "en la captura todo ..."<< endl; \t} \t }' El código anterior libera la memoria sin ningún problema. – Ram

Cuestiones relacionadas