Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mysterious crash with shared_ptr

Tags:

c++

shared-ptr

Can someone please explain why the following crashes in main() when the inner scope is exited? I'm using Visual Studio 2013. Though everything is fine with GCC 4.8.1, I suspect something is wrong in the code anyway. I just don't get it.

#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.
}

The error message I get with VS2013 is:

assertion failure

_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

like image 923
prestokeys Avatar asked Sep 20 '14 14:09

prestokeys


2 Answers

You've got two shared_ptrs trying to own the same pointer (and they don't know about each other). This results in both of them trying to free the same address.

a is trying to take total ownership of this. But then you pass this to CreateProxy() which creates a new shared_ptr that tries to take total ownership of this. The new shared_ptr doesn't know about a, so neither one shares their reference count. shared_ptrs need to share their reference count, not just the pointer itself.

If you want to share a pointer between two shared_ptrs, they need to both know about each other (so they can update their reference count). When Girl calls createProxy(), it needs to pass a shared_ptr to this.

Perhaps this would be a good time to use std::enable_shared_from_this().

like image 107
Cornstalks Avatar answered Sep 30 '22 08:09

Cornstalks


You're creating multiple reference count instances for the same pointer.
Creating a new shred_ptr from a pointer starts a new reference counter. When a reference counter reaches 0, the shared_ptr's default deleter calls delete on that pointer.

Because you have more than one reference counter for that pointer, the delete is called more than once.

like image 33
Yochai Timmer Avatar answered Sep 30 '22 08:09

Yochai Timmer