2010-04-27 17 views
5

Ich stoße auf den folgenden Fehler.Vektor bezogene Speicherzuweisung Frage

  • Ich habe eine Klasse Foo. Instanzen dieser Klasse sind in einem std :: vector vec von class B gespeichert.
  • in Klasse Foo, ich erstellen eine Instanz der Klasse A durch Zuweisen von Speicher mit new und Löschen dieses Objekts in ~Foo().

der Code kompiliert, aber ich bekomme einen Absturz zur Laufzeit. Wenn ich delete my_a von Desstructor der Klasse Foo deaktivieren. Der Code läuft gut (aber es wird ein Speicherleck geben).

Könnte jemand bitte erklären, was hier falsch läuft und eine Reparatur vorschlagen?

danke!

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; 
} 

Antwort

7

Sie müssen einen Kopierkonstruktor und einen Zuweisungsoperator für Foo implementieren. Wann immer Sie einen Destruktor finden, brauchen Sie diese beiden natürlich auch. Sie werden an vielen Stellen verwendet, speziell um Objekte in Standard Library-Container zu legen.

Der Copykonstruktor sollte wie folgt aussehen:

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

und den Zuweisungsoperator:

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

Oder noch besser, nicht dynamisch die A-Instanz in der Foo-Klasse nicht erstellen:

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

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

Dank Neil. Wie sollte ich dann Instanz der Klasse A erstellen? Ein Code-Snippet würde sehr geschätzt werden. Auch, wie Kopie Konstruktor und Zuordnung Operator Code aussehen würde. Vielen Dank – memC

+1

Neil du hast einen Tippfehler ... neu A (f.mein_a); -> neues A (* f.my_a); – TimW

+0

Hallo Neil, vielen Dank für das Code-Snippet. Eigentlich möchte ich das 'int val' für' my_a' übergeben, während Foo in den Vektor eingefügt wird. wie mache ich das? -> Ich möchte so etwas: (natürlich funktioniert es nicht) 'vec.push_back (Foo(): my_a (40)' – memC

2

Das Foo-Objekt wird kopiert und bei der Zerstörung jeder Kopie wird delete auf dem s aufgerufen ame Zeigerwert my_a. Implementieren Sie den Kopier- und Zuweisungsoperator für Foo oder verwenden Sie einen Smartpointer.

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); 
}; 
+0

+1 für Smart-Zeiger – hamishmcn

+0

danke Tim für die Antwort. – memC

3

Wenn Sie keinen Kopierkonstruktor angeben, erstellt der Compiler einen für Sie. Ihr kompilergenerierter Kopierkonstruktor sieht folgendermaßen aus:

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

Woops! Sie kopieren nur den Mauszeiger, nicht aber den Mauszeiger. Sowohl Ihr temporärer Foo() in createFoo() als auch der in den Vektor kopierte Punkt zeigen auf den gleichen Speicher, so dass der Speicher zweimal gelöscht wird, was beim zweiten Löschvorgang Ihr Programm zum Absturz bringt.

Sie sollten eine Kopie Konstruktor erstellen, die etwa wie folgt aussieht:

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

Hinweis: dieser stürzt ab, wenn copy ein NULL my_a Mitglied hat, und es ruft auch den Kopierkonstruktor auf A, die Sie nicht angegeben haben entweder. Sie werden also weitere Änderungen vornehmen wollen. Sie werden auch eine operator= Überladung wollen.