2014-09-20 2 views
5

Kann jemand bitte erklären, warum das folgende in main() abstürzt, wenn der innere Bereich verlassen wird? Ich benutze Visual Studio 2013. Obwohl alles mit GCC 4.8.1 in Ordnung ist, vermute ich, dass etwas im Code sowieso nicht stimmt. Ich verstehe es einfach nicht.Mysteriöser Absturz mit shared_ptr

#include <iostream> 
#include <memory> 

class Person; class PersonProxy; 

class PersonInterface { 
    public: 
     virtual ~PersonInterface() = default; 
     virtual PersonProxy* getProxy() const = 0; 
     virtual void createProxy (Person*) = 0; 
    }; 

class Person : public PersonInterface { 
    private: 
     std::string name; 
     std::shared_ptr<PersonProxy> proxy; 
    public: 
     Person() = default; 
     explicit Person (const std::string& n) : name(n) {} 
    public: 
     virtual PersonProxy* getProxy() const override {return proxy.get();} 
     inline void createProxy (Person* p); 
}; 

class PersonProxy : public PersonInterface { 
    private: 
     std::shared_ptr<Person> actual; 
    public: 
     explicit PersonProxy (Person* p) : actual (std::shared_ptr<Person>(p)) {} 
     explicit PersonProxy (std::shared_ptr<Person> p) : actual (p) {} 
     void rebind (std::shared_ptr<Person> p) {actual = p;} 
     virtual PersonProxy* getProxy() const override {return actual->getProxy();} 
     virtual void createProxy (Person* p) override {actual->createProxy(p);} 
}; 

class Girl : public Person { 
    public: 
     Girl (const std::string& name) : Person (name) {createProxy (this);} 
}; 

inline void Person::createProxy (Person* p) { 
    proxy = std::shared_ptr<PersonProxy>(new PersonProxy(p)); 
} 

int main() { 
    { 
     Girl* a = new Girl("a"); 
//  std::shared_ptr<Girl> a = std::make_shared<Girl>("a"); // Using this crashes with Visual Studio 2013 on the line 'a->getProxy()->rebind(b);' 
     std::shared_ptr<Girl> b = std::make_shared<Girl>("b"); 
     a->getProxy()->rebind(b); 
     std::cout << "rebind succeeded." << std::endl; 
    } 
    std::cout << "Exited scope." << std::endl; // Exiting scope crashes with VS 2013. 
} 

Die Fehlermeldung, die ich mit VS2013 erhalten ist:

Assertionsfehler

_BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)

+0

Der Code ist ziemlich klein, warum nicht mit einem Debugger durchlaufen? –

+0

@CaptainObvlious würde es wirklich helfen? –

+0

@ n.m. Wahrscheinlich nicht, aber ich bin ein Masochist, bis ich meine Morgenschale mit Fruity Pebbles hatte. –

Antwort

9

Sie erstellen mehrere Referenzzähler-Instanzen für den gleichen Zeiger.
Das Erstellen eines neuen shred_ptr aus einem Zeiger startet einen neuen Referenzzähler. Wenn ein Referenzzähler den Wert 0 erreicht, löschen die Standardlöscheraufrufe von shared_ptr diesen Zeiger.

Da Sie mehr als einen Referenzzähler für diesen Zeiger haben, wird das Löschen mehr als einmal aufgerufen.

13

Sie haben zwei shared_ptr s versuchen, den gleichen Zeiger zu besitzen (und sie wissen nicht voneinander). Dies führt dazu, dass beide versuchen, dieselbe Adresse freizugeben.

a versucht, den gesamten Besitz von this zu übernehmen. Aber dann übergeben Sie this an CreateProxy(), die eine neueshared_ptr erstellt, die versucht, den gesamten Besitz von this zu übernehmen. Die neue shared_ptr weiß nicht über a, so dass keiner ihre Referenzzahl teilt. shared_ptr s müssen ihre Referenzzählung teilen, nicht nur den Zeiger selbst.

Wenn Sie einen Zeiger zwischen zwei shared_ptr s teilen möchten, müssen beide voneinander wissen (damit sie ihre Referenzzählung aktualisieren können). Wenn GirlcreateProxy() aufruft, muss ein shared_ptr an this übergeben werden.

Vielleicht wäre dies eine gute Zeit, std::enable_shared_from_this() zu verwenden.

+0

Also Mädchen muss von std :: enable_shared_from_this und in seinem Konstruktor Aufruf 'createProxy (shared_from_this());' ? Was bedeutet, dass Person eine createProxy (std :: shared_ptr ) Überladung haben muss? – prestokeys

+0

@prestokeys: Warum verwenden Sie all diese Proxy-Sachen. –

+0

@Cheers. Es ist eine lange Erklärung. Ich habe mit einigen professionellen Programmierern bestätigt, dass es für mein Programm benötigt wird. Aber ich habe das obige Problem immer noch nicht behoben mit std :: enable_shared_from_this noch (immer noch den Kopf kratzt). – prestokeys