Ahana Pradhan
Ahana Pradhan

Reputation: 117

Double deletion error with shared_ptr C++

I have the following class design:

struct compare{
template <typename T>
bool operator()(const T& a, const T&b){ return *a < *b;}
};

class Trans;

typedef set<shared_ptr<Trans>, compare > TransPointerSet;

class Place{

  // other data members
 TransPointerSet nextTrans;

public:

  // constructor and other methods including overloaded < operator
  void insertNextTrans(shared_ptr<Trans> t){ nextTrans.insert(t); }
  void removeNextTrans() { nextTrans.clear(); }

};

typedef set<shared_ptr<Place>, compare > PlacePointerSet;

class Trans{

//other data members
PlacePointerSet inPlaces;
PlacePointerSet outPlaces;

public:

//constructor and others including overloaded < operator
void insertInPlace(shared_ptr<Place> p){ 
     inPlaces.insert(p); 
     p->insertNextTrans(shared_ptr<Trans>(this)); }
void insertOutPlace(shared_ptr<Place> p){ //body }
void print() cosnt { //body }

};

class Net{
TransPointerSet acts;
//other data members
public:
//constructor and others
};

And here is my main for testing whether the classes are properly working or not.

int main()
{
 shared_ptr<Place> p1 = make_shared<Place>();
shared_ptr<Place> p2 = make_shared<Place>();
shared_ptr<Trans> t = make_shared<Trans>();
t->insertInPlace(p1);
t->insertOutPlace(p2);
t->print();
}

The problem is after successful compilation it ends up with "double free or corruption (fasttop) error" after t->print() properly working. I realize the bug lies in the circular dependency created by firstly taking p1 as member of t->inPlaces which inserts t as member of p1. But I need this both way linking. Also, I tried to reset every member of nextTrans in class Place by a method after t->print(), but that didn't work because the pointers are in a set. So can anyone suggest any way to fix this problem?

Upvotes: 1

Views: 2031

Answers (2)

Michael Burr
Michael Burr

Reputation: 340188

This line in Trans::insertInPlace():

p->insertNextTrans(shared_ptr<Trans>(this)); 

creates a separate, unrelated shared pointer to the same object. You need to use std::enable_shared_from_this for the Trans class:

class Trans: public std::enable_shared_from_this {
    // ....
};

Then in Trans::insertInPlace():

p->insertNextTrans(shared_from_this());

Upvotes: 5

Some programmer dude
Some programmer dude

Reputation: 409166

It's because you can't make a shared pointer from this just like that. By doing it you now have two shared pointers to the Trans instance, both pointing to the same instance but with their separate reference counters. That means that both will try to delete the pointer.

You need to use std::enable_shared_from_this. The linked reference page have a very good example of your problem.

Upvotes: 6

Related Questions