2010-06-01 16 views
7

No puedo entender por qué el siguiente código produce pérdidas de memoria (estoy usando boost::shared_ptr con una instancia de clase estática). ¿Alguien podría ayudarme?C++ static classes & shared_ptr memory leaks

#include <crtdbg.h> 
#include <boost/shared_ptr.hpp> 
using boost::shared_ptr; 

#define _CRTDBG_MAP_ALLOC 
#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) 

static struct myclass { 
    static shared_ptr<int> ptr; 

    myclass() { 
     ptr = shared_ptr<int>(NEW int); 
    } 
} myclass_instance; 

shared_ptr<int> myclass::ptr; 

int main() { 
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | 
        _CRTDBG_CHECK_ALWAYS_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); 
    return 0; 
} 
+0

¿Por qué hay una segunda llamada a '_CrtSetDbgFlag()' dentro de los parámetros or-list? – sharptooth

+0

Es una forma de combinar dos declaraciones en una sola –

+0

No lo entiendo. ¿Por qué no "o" cuatro banderas, sino que llama a la función dentro de la lista "o"? – sharptooth

Respuesta

8

En una estimación del CRT está reportando un falso positivo - el código siguiente ilustra que el puntero compartida está funcionando correctamente, al menos con g ++

#include <iostream> 
#include "boost/shared_ptr.hpp" 
using namespace std; 
using namespace boost; 

struct R { 
    R() { 
     cerr << "ctor" << endl; 
    } 

    ~R() { 
     cerr << "dtor" << endl; 
    } 
}; 

struct A { 
    static shared_ptr<R> ptr; 

    A() { 
    ptr = shared_ptr<R>(new R); 
    } 

}; 

shared_ptr<R> A::ptr; 
static A a; 

int main() { 
} 

Imprime:

ctor 
dtor 
+0

+1 para el código de prueba – neuro

8

Lo más probable es que se detecta la fuga antes de que los objetos globales se destruyen y shared_ptr tiene la oportunidad de liberar el objeto, por lo que es probable que una falsa fuga.

11

Este es una pérdida de memoria Está inicializando una instancia estática de myclass llamada myclass_instance. También está inicializando el "shared_ptr myclass :: ptr".

Según Stroustrup [3], las estadísticas se inicializan en el orden en que se definen. Por lo tanto, tiene la definición estática de myclass_instance, que inicializa el ptr interno en la construcción. Sin embargo, tiene la definición de static myclass :: ptr, que invoca el constructor predeterminado para shared_ptr.

Este es un ejemplo del clásico problema de pedidos estáticos. El compilador cree que myclass :: ptr en realidad no se inicializó, por lo que no hay destrucción del shared_ptr original. En cambio, solo se filtró.

Necesitará un puntero de algún tipo. Si está utilizando C++ 11, puede hacer la técnica de contador ingenioso con una declaración de asignación ternaria que hace un movimiento a sí mismo si determina que el objeto ya se ha inicializado. Es bastante duro, pero funciona.

Así es como lo haría en C++ 11:

#include <crtdbg.h> 
#include <memory> 
using std; 

#define _CRTDBG_MAP_ALLOC 
#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) 

// Note that the count could also be a field in an initializer static used in the Nifty Counter 
// Technique covered in many texts. 
static int count = 0; // This gets implicitly initialized to 0 by the executable load into memory. 
static struct myclass { 
    static shared_ptr<int> ptr; 

    myclass() { 
     if (count++ == 0) { 
     ptr = make_shared<int>(0); //initialization 
     } 
    }   
} myclass_instance; 

shared_ptr<int> myclass::ptr = count == 0 ? make_shared<int>(0) : move(myclass::ptr); 

int main() { 
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | 
        _CRTDBG_CHECK_ALWAYS_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); 
    return 0; 
} 

Véase lo siguiente para más información:

  1. Lakos, J, 1996, a gran escala C++ Diseño de Software. Sección 7.8.1.3, Addison Wesley, Reading, Massachusetts.
  2. Meyers, S, 2005, vigente C++, tercera edición. Artículo 4: asegúrese de que los objetos estén inicializados antes de ser utilizados. Addison Wesley, Reading, Massachusetts.
  3. Stroustrup, B, 2000, The C++ Programming Language Special Edition. Sección 10.4.9, Addison Wesley, Reading, Massachusetts.
+0

Creo que esta es la única respuesta correcta, la respuesta anterior de anon no es una transcripción correcta ya que el orden de A y A :: ptr es diferente. –