2010-06-01 3 views
7

Je ne comprends pas pourquoi le code suivant produit des fuites de mémoire (j'utilise boost::shared_ptr avec une instance de classe statique). Quelqu'un pourrait-il m'aider?Classes statiques C++ et fuites de mémoire shared_ptr

#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

Pourquoi y at-il un deuxième appel à '_CrtSetDbgFlag()' dans la liste des paramètres? – sharptooth

+0

C'est un moyen de combiner deux déclarations en une seule –

+0

Je ne comprends pas. Pourquoi ne pas "ou" quatre drapeaux mais appeler la fonction insidethe la liste "ou"? – sharptooth

Répondre

8

A une estimation du CRT rapporte un faux positif - le code suivant montre que le pointeur partagé fonctionne correctement, au moins avec 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() { 
} 

Il imprime:

ctor 
dtor 
+0

+1 pour le code de test – neuro

8

Très probablement la fuite est détectée avant que les objets globaux sont détruits et shared_ptr a une chance de libérer l'objet, il est donc probable une fausse fuite .

11

C'est une fuite de mémoire. Vous initialisez une instance statique de myclass appelée myclass_instance. Vous initialisez également le "shared_ptr myclass :: ptr". Selon Stroustrup [3], les statiques sont initialisées dans l'ordre où elles sont définies. Par conséquent vous avez la définition statique de myclass_instance, qui initialise le ptr interne sur la construction. Cependant, vous avez alors la définition du static myclass :: ptr, qui appelle le constructeur par défaut pour shared_ptr.

Ceci est un exemple du problème classique d'ordre de la statique. Le compilateur pense que myclass :: ptr n'a pas été initialisé, donc il n'y a pas de destruction du shared_ptr original. Au lieu de cela, il est juste fuite.

Vous aurez besoin d'un pointeur nu de quelque sorte. Si vous utilisez C++ 11, vous pouvez faire la technique Nifty Counter avec une instruction d'assignation ternaire qui se déplace sur elle-même si vous déterminez que l'objet a déjà été initialisé. C'est plutôt dur, mais ça fonctionne.

Voilà comment je le ferais 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; 
} 

Voir les éléments suivants pour plus d'informations:

  1. Lakos, J, 1996, à grande échelle C++ Logiciel de conception. Section 7.8.1.3, Addison Wesley, Reading, Massachusetts.
  2. Meyers, S, 2005, en vigueur C++, troisième édition. Rubrique 4: Assurez-vous que les objets sont initialisés avant de les utiliser. Addison Wesley, Reading, Massachusetts.
  3. Stroustrup, B, 2000, Édition spéciale du langage de programmation C++. Section 10.4.9, Addison Wesley, Reading, Massachusetts.
+0

Je pense que c'est la seule bonne réponse, une réponse antérieure par anon n'est pas une transcription correcte puisque l'ordre de A et A :: ptr est différent. –