Pergunta

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?

Foi útil?

Solução

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.

Outras dicas

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());
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top