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)
You've got two shared_ptr
s 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_ptr
s need to share their reference count, not just the pointer itself.
If you want to share a pointer between two shared_ptr
s, 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()
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With