5 votes

Question sur l'allocation de mémoire liée aux vecteurs

Je rencontre le bug suivant.

  • J'ai une classe Foo . Les instances de cette classe sont stockées dans un std::vector vec de class B .
  • dans la classe Foo, je crée une instance de la classe A en allouant de la mémoire à l'aide de la fonction new et en supprimant cet objet dans ~Foo() .

le code se compile, mais j'obtiens un crash au moment de l'exécution. Si je désactive delete my_a du destructeur de la classe Foo . Le code fonctionne bien (mais il va y avoir une fuite de mémoire).

Quelqu'un pourrait-il expliquer ce qui ne va pas ici et suggérer une solution ?

Merci !

class A{
      public:
          A(int val);
          ~A(){};
          int val_a;

};

A::A(int val){
       val_a = val;
       };

class Foo {      
      public:
             Foo();
             ~Foo();
             void createA();
             A* my_a;
};

Foo::Foo(){
    createA();
};

void Foo::createA(){
    my_a = new A(20);
};

Foo::~Foo(){
    delete my_a;

};

class B {
      public:
             vector<Foo> vec;             
             void createFoo();            
             B(){};
             ~B(){};
};

void B::createFoo(){
    vec.push_back(Foo());
};

int main(){
    B b;

    int i  =0;
    for (i = 0; i < 5; i ++){
        std::cout<<"\n creating Foo";
        b.createFoo();   
        std::cout<<"\n Foo created";
        }
    std::cout<<"\nDone with Foo creation";

    std::cout << "\nPress RETURN to continue...";
    std::cin.get();

    return 0;
}

7voto

Vous devez implémenter un constructeur de copie et un opérateur d'affectation pour Foo. Chaque fois que vous aurez besoin d'un destructeur, vous aurez très certainement besoin de ces deux-là aussi. Ils sont utilisés à de nombreux endroits, notamment pour placer des objets dans des conteneurs de la bibliothèque standard.

Le constructeur de copie devrait ressembler à ceci :

Foo :: Foo( const Foo & f ) : my_a( new A( * f.my_a ) ) {
}

et l'opérateur d'affectation :

Foo & Foo :: operator=( const Foo & f ) {
    delete my_a;
    my_a = new A( * f.my_a );
    return * this;
}

Ou mieux encore, ne créez pas dynamiquement l'instance A dans la classe Foo :

class Foo {      
      public:
             Foo();
             ~Foo();
             void createA();
             A my_a;
};

Foo::Foo() : my_a( 20 ) {
};

3voto

AshleysBrain Points 11439

Si vous ne spécifiez pas de constructeur de copie, le compilateur en fait un pour vous. Votre constructeur de copie généré par le compilateur ressemble à ceci :

Foo::Foo(const Foo& copy)
    : my_a(copy.my_a)
{}

Oups ! Vous copiez juste le pointeur mais pas la mémoire pointée. Vos deux mémoires temporaires Foo() sur createFoo() et celle copiée dans le vecteur pointent vers la même mémoire, donc la mémoire est supprimée deux fois, ce qui fait planter votre programme à la deuxième suppression.

Vous devez créer un constructeur de copie qui ressemble à quelque chose comme ceci :

Foo::Foo(const Foo& copy)
    : my_a(new A(*copy.my_a))
{}

Notez que cela se bloque si copy a un NULL my_a et invoque également le constructeur de copie sur le membre A ce que vous n'avez pas précisé non plus. Vous devrez donc procéder à d'autres modifications. Vous voudrez aussi un operator= la surcharge aussi.

2voto

TimW Points 5715

L'objet Foo est copié et à la destruction de chaque copie, delete est appelé sur la même valeur de pointeur my_a. Implémentez l'opérateur de copie et d'affectation pour Foo ou utilisez un pointeur intelligent.

 Foo( const Foo& s) : my_a( s.my_a ? new A(*s.my_a) : 0) {
 }

 Foo& operator= (const Foo& s) {
     Foo temp(s); 
     temp.swap (*this);
     return *this;
 }

 void swap (Foo &s) { 
     std::swap (my_a, s.my_a);  
 };

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X